组件库会包含几十甚至上百个组件,但是应用的时候往往只使用其中的一部分。这个时候如果全部引入到项目中,就会使输出产物体积变大。按需加载的支持是组件库中必须考虑的问题。
目前组件的按需引入会分成两个方法:
- 经典方法:组件单独分包 + 按需导入 +
babel-plugin-component
(自动化按需引入); - 次时代方法:
ESModule
+Treeshaking
+ 自动按需import
(unplugin-vue-components
自动化配置)。
经典方法
目前多数主流组件库实现按需引入的方式使用的是经典方法,而使用经典方法的基础是,组件单独分包。
最简单的按需引入
因为每个组件都是一个单独的包,我们可以只引入某个组件,比如:
import Button from 'xxx-ui/packages/button';
import 'xxx-ui/theme-chalk/button.css';
Vue.use(Button);
这样我们就只引入了Button
相关的文件,而不会包含其他组件。这样的问题是比较麻烦,使用成本较高,使用者需要知道组件库的一些路径等。最理想的方式还是下面这种:
import { Button } from 'xxx-ui';
通过 babel 插件实现转换
既然想通过以上这种简单的方式引入组件和相关的样式文件等文件,那么我们只要帮使用者把第一种方式转换成第二种就可以了。而通过babel
插件来转换对用户来说是无感的。主流组件库也是这样实现的,比如Element UI
使用的是babel-plugin-component
插件。大致思路就是这样,如果需要实现这种方式的按需引入,则需要为自己的组件库开发一个类似的babel
插件,通过AST
抽象语法树进行一个转换。具体实现可参考babel-plugin-import源码。
Ant Design
也是采用这种方式,只是使用的插件不一样。它用的是babel-plugin-import
,其实babel-plugin-component
就是fork
自babel-plugin-import
的。
次时代方法
除了组件独立分包后通过babel
插件实现按需引入的转换这种经典方法,还有种更简单的方法,即利用Tree-shaking
。
组件库应打包为 es module 模块
commonjs
规范是最常见的使用方式,umd
一般用于CDN方式直接在页面引入,而es module
就是用来实现Tree Shaking
的,为什么es module
能实现Tree Shaking
而commonjs
规范不行呢,原因是es module
是静态编译的,也就是在编译阶段就能确定某个模块导出了什么,引入了什么,代码执行阶段不会改变,所以打包工具在打包的时候就能分析出哪个方法被使用了,哪些没有,没有用到的就可以放心的删掉了。
此外,需要在组件库的package.json
文件中的"module"
属性指定包的es module
模块入口,会优先于"main"
属性生效。
组件库应按规范导出各组件
接下来我们还要修改一下组件库中各组件的导出方法,不独立分包,所有组件暴露在一个入口文件中。这样才能支持以下这种使用方式:
import { Button } from 'xxx-ui';
我们需要保证最终在入口文件(如index.js
)中导出各具名组件,如:
// 可以在入口文件引入全局样式文件,同时配置 sideEffects 以保证 tree-shaking 不会把样式文件移除
// import './style.css';
// 如果没有配置 sideEffects 在主项目中使用组件库时还需要手动引入打包产物中的样式文件
// ...
import XButton from '@/components/button';
import XInput from '@/components/input';
import XDialog from '@/components/dialog';
// ...
export {
XButton,
XInput,
XDialog,
// ...
}
// ...
按需配置 sideEffects
我们在入口文件中引入了全局样式文件style.css
,但是并没有明显的进行使用,这时,tree-shaking
就会把这种没有明显进行使用的模块移除。但我们显然是不想让样式文件被移除的,这样在主项目中就不需要再手动显式引入样式文件了。
那么我们就需要告诉主项目的打包工具哪些文件是没有副作用的,可以删掉,哪些是有的,需要保留。如果主项目的打包工具是webpack
,那么我们就需要在package.json
文件中新增一个sideEffects
属性:
{
// ...
"sideEffects": ["**/*.css"],
// ...
}
这样就大功告成了。
使用 unplugin-vue-components 插件实现自动引入
有些主流组件库还支持自动按需引入你使用的组件,使用者可以在模板里直接使用,由插件来扫描引入并注册。当然,这个插件还需要我们自己实现。具体实现可参考unplugin-vue-components
插件的实现或其他开源插件的实现。
Comments NOTHING