(给 前端大全加星标,提升前端技能 )
作者:FlyTeng_1874
https://juejin.cn/post/6844904021870772232
始
很多时候,我们为了复用或者归纳总结,会把组件抽离出来发到npm 上。但是这个过程你会发现一个问题,就是应该怎么更好的发布 和管理 维护这些组件呢。最后会发现网上的其他教程不是太零散了,就是有些细节不大到位。这里借这个机会好好总结一下,要是看完觉得有帮助的话,不妨个赞 ,关注一下哈哈。
理解完之后我们就可以
-
编写发布一个可用的组件库
-
能以
import { demoComponent } from 'xxxUI'方式引入 -
也能以
import demoComponent from xxxUI/component/demoComponent方式引入 -
各个组件
打包相对独立,互不干扰 -
输出的组件能够
简单易用和具有良好的兼容性 -
组件库能根据用户的配置实现
按需加载 -
组件库能根据用户的配置实现
Tree Shaking -
组件通过
单元测试 -
打包发布到
npm
就像这样,嘿嘿。
以下都以react组件库为例,其实vue是也一样的,只是babel配置有所区别
项目结构
结构解析
先来看看组件库的项目结构
嗯,看起来很是复杂,第一印象应该都在想着都是些什么乱七八糟的文件,下面先来解释一下。
-
src存放核心代码 -
dist存放最后打包输出的代码 -
sass样式单独抽离放置(当然可以跟组件放一起,这里的目的是即使不用相关的组件,单独使用相关样式也是没问题) -
__mocks__(mock对象),coverage(覆盖率),test,jest.config.js(jest配置)这些都是与单元测试相关的下一章会有详细介绍 -
.npmignore与.gitignore作用类似 -
.babelrc大名鼎鼎的babel应该都知道的 -
其他应该都非常熟悉了,再介绍下去就有凑字数的嫌疑了。
关键目录
我们先把目光聚焦到src 核心代码目录下,首先我们将组件存放在component 中,在外层用index 去引用component 中的组件,由于在不提供具体路径的情况下,import 引入时会默认找到index 。这样在打包输出后,就能通过import { demoComponent } from 'xxxUI' 这种方式去引用组件了。
然后使用这种形式去导出组件,就能通过import demoComponent from xxxUI/component/demoComponent 这种形式单独引入组件了。
组件库按需加载
根据以上目录结构和引入方式我们可以知道,通过import { demoComponent } from ' xxxUI' 这种形式去引入会使得整个组件库都引入到开发项目中,有时只需要用到其中的两三个组件,这种情况是我们不想看到的。而通过import demoComponent from xxxUI/component/demoComponent这种形式去引用,就能做到只引入某个需要用到的组件,这刚好能解决这个问题。但是每次引入都要写这么长的一串,很不方便。这个时候就需要用到
babel-plugin-import这个插件了。
import { demoComponent, demoComponent1, demoComponent2 } from 'xxxUI'
// 使用
babel-plugin-import插件能自动将以上这种调用形式在
AST(抽象语法树)中改写成以下形式。// 这样就能方便地引入相关组件,又不用担心一次全部引入导致包过大的问题
需要注意的是,这里需要组件库的使用者去配置,而不是写在组件库的
.babelrc中。如果组件库支持按需加载,这个配置应该写在README.md中交由组件库的使用者去选择。按需加载的好坏处是由具体的项目环境而定,需要具体情况具体分析。
没设置按需加载时,整个组件库都打包进去了。
设置了按需加载,只加载用到的组件。
就这样,通过巧妙的文件结构,目标2,3,6 已达成。
输入
明确了项目结构,接下来就是需要收集组件源码了。通常来讲,只需要在webpack 的entry 配置中只需要设置入口文件index 就可以了,就像这样entry: path.resolve(__dirname, 'src', 'index.jsx ')。但由于我们需要每个组件互相独立单独打包,所以需要一个个组件去引入,同时也要保持相应的文件结构。
在这里使用了glob 这个很好用的工具,能很方便匹配出对应的文件。最后返回的是一个文件路径的映射对象,我们可以在控制台看看输入了哪些文件。
ok,接下来就是要怎样处理这些源文件了。
编译处理和组件库Tree Shaking
这里的处理过程很简单,逻辑就是配置babel 将es6+ 的源码处理成es5 的兼容代码,顺便也将svg 小图标转化为base64 格式嵌入。这样做更多是为了让用户以尽量小的配置,尽量小的上手成本就能使用这个组件库。这里如果同时保留了es6 代码,就能够让让开发者可以自由配置Tree Shaking 了(比如开发者只用到了某个组件中的某个方法的场景下,就没必要引入整个组件了)。关于开发者如何配置Tree Shaking 最后会讲到。
Es6 Modules从语法层面提供了模块化功能,
Tree Shaking就是基于ES6模块化的,在编译打包节点可以在AST(抽象语法树)中静态分析,将没有用到的代码剔除掉。我们经过编译打包后的es5代码是无法进行Tree Shaking的。
达成目标的第7点。
输出
打包编译输出到dist 目录,要注意的是dist 目录中的结构要与src 目录保持一致才能使组件和组件间的引用路径不会乱,就像这样,dist 目录结构跟src 相似。
再来看看output 的配置,由于我们在文件输入时保持了文件路径信息,所以这里直接更改后缀之后输出到dist即可。libraryTarget 的作用在于设置打包格式,这里采用umd 标准。如果设置了library ,那么将会导出成单入口的引用形式import xxxUI from 'xxxUI ',这是我们不希望的。 library 与libraryTarget 的取值根据项目类型的不同而不同。
万事俱备了,但按照这样打包后会发现,怎么第三方包react,react-dom 也跟着打包进来了,这会导致打包之后组件库的体积很大。
我们需要这样去配置,过滤掉import 进来的第三方包
可以看到变化巨大!现在整个包大小只有120kb (除去样式)
由于样式是独立抽离 出来的,只需要将样式copy到dist 目录即可,当然可配置插件自动完成。
new CopyPlugin([{from: './sass', to: './sass'}])
达成目标的4,5点
最终发布
-
先去官网完成注册
-
npm login登录(这里一定要先切换到国外镜像源) -
添加
.npmignore文件,将需要忽略的文件列出来 -
添加
README.md,写出必要的说明,这是一个好习惯 -
在
package.json的script中添加命令webpack --mode production && npm publish ./dist。这里意思是采用生产模式打包并将dist目录发布上npm。
到最后README.md 使用手册可以这样写
babel中modules的选项有
'amd' | 'umd' | 'systemjs' | 'commonjs' | false这几个,由于Tree Shaking基于ES6 Modules,这里就不能转换成其他标准,只能选false,即采用原本文件的模块标准编译。
搞定,一个实用的组件库就发布完成了,快来动手试试吧。
推荐阅读 点击标题可跳转
觉得本文对你有帮助?请分享给更多人
关注「前端大全」加星标,提升前端技能
好文章,我在看❤️