打包 Vue 组件库的正确姿势
为了方便其他开发者使用组件库,开发的 Vue 组件库在发布之前需要对其打包。本文基于 Webpack 讨论打包 Vue 组件库的正确方法。
选择正确的打包格式
首先,我们必须明确组件库的使用场景。有些场景是直接使用 <script>
在 HTML 中引入,有些场景是使用打包工具在后台构建。作为组件库,应该兼容这些使用场景。组件库应该保持中立,不应该限定于某种使用方式或者打包工具。例如,虽然 Webpack 很流行,组件库不能声明只支持 Webpack 方式使用,忽略了其他选择。原因在于,打包工具并不只有 webpack,还有 browserify、rollup 等。另外,前端工具发展很快,今年流行的工具明年可能就没人用了,你肯定不希望你的组件库会随着某个工具不流行而消逝吧。回顾下曾经流行的 grunt、glup,一大堆基于它们的插件随着工具本身的不流行而被扔进了垃圾箱。
为了支持多种使用场景,我们需要选择合适的打包格式。常见的打包格式有 CMD、AMD、UMD,CMD只能在 Node 环境执行,AMD 只能在浏览器端执行,UMD 同时支持两种执行环境。显而易见,我们应该选择 UMD 格式。Webpack 中指定输出格式的设置项为 output.libraryTarget
,其支持的格式有:
- “var” - 以一个变量形式输出: var Library = xxx (default);
- “this” - 以 this 的一个属性输出: this[“Library”] = xxx;
- “commonjs” - 以 exports 的一个属性输出:exports[“Library”] = xxx;
- “commonjs2” - 以 module.exports 形式输出:module.exports = xxx;
- “amd” - 以 AMD 格式输出;
- “umd” - 同时以 AMD、CommonJS2 和全局属性形式输出。
以下是 webpack.config.js
中 output
设置的示例:
1 | output: { |
到此,我们解决了组件库输出的问题。
如何打包组件依赖
在前一篇文章中我们讨论了组件库实质上是 Vue 的插件,Vue 应该是组件库的外部依赖。组件库的使用者会自行导入 Vue,打包的时候,不应该将 Vue 打包进组件库。
在 webpack 中,我们可以将 Vue 设置为 externals
,以避免将 Vue 打包进组件库,相应的设置如下:
1 | externals: { |
啊哈,我们搞定了组件依赖问题。至此,读者可能很皱起眉头开始埋怨我了:这么简单的问题,查下 webpack 文档不就得了,还用得着我啰里啰嗦地写这么多!
事实上,问题往往没有我们想得那么简单!如果你将打包后的组件库以 <script>
标签形式直接引入,你会发现并不能正常执行,提示 vue 未定义。
为了分析问题,我们将打包的代码前几行拿出来看看:
1 | (function webpackUniversalModuleDefinition(root, factory) { |
我们可以看见,打包后的代码以 4 种形式声明了 Vue 依赖:
module.exports = factory(require("vue"))
- commonjs2 形式;define("iview", ["vue"], factory)
- AMD 形式;exports["iview"] = factory(require("vue"))
- commonjs 形式;root["iview"] = factory(root["vue"])
- 全局变量形式。
以 <script>
标签形式使用组件时,会同样使用 <script>
标签导入 Vue。Vue 导入的变量是 “window.Vue” 而不是 “window.vue”,因此会出现 vue 未定义的错误。
幸好,webpack 可以为各种导入形式设置不同名称,设置如下:
1 | externals: { |
再次打包,你可以发现打包的组件库不管是 <script>
标签方式还是后端构建,都可以正常工作了。
最后,帖一个打包 iView 组件库的 webpack 配置:
1 | var path = require('path'); |
Author: jingsam
Link: https://jingsam.github.io/2016/11/17/bundle-vue-components.html
License: 知识共享署名-非商业性使用 4.0 国际许可协议