按需引入组件库的几种方式
之前升级项目的ui版本时,ui组件的版本错误。无论修改npm版本还是cdn版本均无法解决。
经过同事 @东哥 的排查,发现是样式被覆盖,去除项目中的某sdk组件可恢复正常。
细究原因,项目和sdk中引入了相同ui组件,sdk是使用webpack打包的文件,打包成一个总文件,项目中ui组件版本被覆盖,导致项目样式错误。
// 后续发现应该是 没有把ui组件在打包时externals掉,引入了css文件
同时后续决定了解关于项目实现按需引入的方式。
手动引入
在没有其他辅助手段的情况下,实现按需引入,仅引入需要使用的组件即可。
1 | // test/index.js |
结论
手动引入的方式, 需要深入了解组件库代码,了解各组件位置等信息,不方便。
因此,现在大部分组件库已经放弃了这种方式。
Babel-plugin-import插件
让程序帮我们把引入组件的语句转化成手动引入的语句
1 | // test/index.js |
配置.babelrc文件
1 | // test/.babelrc |
结论
Babel-plugin-import借助Babel解析编辑ATS的能力实现了一种成熟的组件按需引入方式。
优点:只需要按照babel文档进行配置即可
缺点:代码中需增加本无需的Babel及相关的配置
Tree-Shaking
Tree Shaking
中文含义是摇树,在webpack中作用是消除不可能执行的代码。
而webpack5
已经自带了这个功能了,当打包环境为production
时,默认开启tree-shaking
功能。
Tree-shaking是依赖ESM这种模块引入方式的:
ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,从而构成了tree-shaking的基础。
所谓静态分析就是不执行代码,从字面量上对代码进行分析,可以想一下在commonjs的模块化中我们可以动态require一个模块,只有执行后才知道引用的什么模块,这个就不能通过静态分析去做优化。总之就是一句话——代码是否有用只有在编译时分析,才不会影响运行时的状态。
在webpack中使用tree-shaking,webpack官方文档的总结如下:
我们学到为了利用 tree shaking 的优势, 你必须…
1、使用 ES2015 模块语法(即 import 和 export)。
2、确保没有编译器将您的 ES2015 模块语法转换为 CommonJS 的(顺带一提,这是现在常用的 @babel/preset-env 的默认行为,详细信息请参阅文档)。
3、在项目的 package.json 文件中,添加 “sideEffects” 属性。
4、使用 mode 为 “production” 的配置项以启用更多优化项,包括压缩代码与 tree shaking。
webpack5中,mode为production
时,已自动开启DCE工具(消除无用代码)UglifyJSPlugin和tree-shaking
组件库打包:支持按需加载
根据以上我们得知,组件库支持按需加载需满足:
- 组件库以es6模块化方式导出(注意babel)
- package.json中添加sideEffects属性
- 宿主项目中引用方式写法到位或者配置了babel-plugin-import
- 宿主项目通过webpack打包支持tree-shaking
实现按需加载存在的问题
webpack不支持ESM导出
webpack umd 形式导出,打包出来的东西才能供别人使用
1 | // webapack.config |
但是是整体定义成一个模块,不能支持按需加载
解决方式:
- 使用支持ESM模块导出的Gulp进行打包。
- 放弃或限制Babel的使用,毕竟能导入ESM代码的项目应该是支持ES6语法的。
- 不支持ES6模块引入的项目,我们继续采用上述的webpack打包方式。