# 搭建组件库
利用 webpack,通过入口将所有的组件模块导入并且注册,然后通过生成一个 bundle.js 文件即可。
# 创建 vue 项目
创建 vue 项目,除了 vue 项目自带的文件目录外,在根目录下添加以下目录结构:
└───build 目录:主要存放 webpack 相关配置
| └───webpack.build.config.js // 打包生成组件库 webpack 配置
|───lib 目录:打包生成的 bundle.js 目录
| └───bundle.js // 打包生成的 bundle
|───packages
| └───index.js // 注册所有组件脚本文件
| └───组件名称 1
| └───src
| └───index.vue // 组件源码
| └───index.js // 单个组件注册
| └───组件名称 2
| └───src
| └───index.vue // 组件源码
| └───index.js // 单个组件注册
| └───组件名称 n
| └───...
# 添加生成组件库 webpack 配置
配置目录:build/webpack.biuld.config.js
# entry
入口作用:入口将所有的组件模块导入并且注册。
entry: {
xx: path.resolve(__dirname, '../packages/index.js'),
}
# output
output: {
path: path.resolve(__dirname, '../lib'),
publicPath: '/lib/',
library: 'xx', // 包名
libraryTarget: 'umd',
umdNamedDefine: true,
}
其中,libraryTarget (opens new window) 采用 umd 格式。
打包后的 library 暴露为所有的模块定义下都可运行的方式。它将在 CommonJS, AMD 环境下运行,或将模块导出到 global 下的变量。
# loader
babel-loader(@babel/preset-env、@babel/transform-runtime、dynamic-import-webpack)、vue-loader、css-loader、postcss-loader、sass-loader、url-loader。
静态资源如图片等统一转化成 base64,后面统一使用 iconfont 的方式使用图标。
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg|ttf|woff|woff2|eot)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10240000,
name: 'static/[name].[hash:6].[ext]',
esModule: false, // https://webpack.docschina.org/loaders/url-loader/#esmodule
},
},
],
},
{
test: /\.css$/i,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
],
},
{
test: /\.s[ac]ss$/i,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
// 将 Sass 编译成 CSS
'sass-loader',
],
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
],
}
# plugins
vue-loader
plugins: [
new VueLoaderPlugin(),
new webpack.LoaderOptionsPlugin({
options: {
errorDetails: true,
},
}),
],
# externals
externals 文档链接 (opens new window)
防止将某些
import
的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。
由于是封装组件库,有使用到如 element-ui 等第三方依赖,所以不需要再对第三方依赖包进行打包。在安装私有库的时候,会自动安装第三方依赖。
externals: [
{
vue: {
root: 'Vue',
commonjs: 'vue',
commonjs2: 'vue',
amd: 'vue',
},
lodash: {
root: 'lodash',
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
},
// 'element-ui': 'element-ui',
vuedraggable: 'vuedraggable',
},
/element-ui[\s\S]+/ig,
]
# 修改 package.json 入口
package.json 入口指向打包好的 bundle.js
{
// ...
"main": "lib/xx.js"
}
# 发布
# 方式一: 发布到 npm
通过 npm publish 发布到 npm 上,使用的时候通过 npm i xx
即可。
# 方式二:放到个人 gitlab / github
使用的时候,添加依赖到 package.json 中:
"xxx": "git+https://xxxxx.git",
删除 node_modules,重新安装依赖即可。
# 优化
原先打包处理的之后一个 bundle.js,这样在实际使用过程中没法做到按需加载。【参考链接 (opens new window)】
在打包过程中,因为是全量加载,这样冗余代码都会被打包,这样明显是不合理的。
主要做两个优化:
- 优化打包策略
配合插件 babel-plugin-component (opens new window) 使用- 配合 Babel 插件 babel-plugin-import (opens new window) 使用
# 插件使用
babel-plugin-import (opens new window) 这个插件会对 import 进行转化。
[
'import',
{
libraryName: 'xxx', // 包名
},
'xxx', // 包名
]
转化前:
import { button } from 'xxx'
转化为:
var button = require('xxx/lib/button/index.js')
# 调整打包策略
这样除了 bundle.js,还需要将每个组件打包成独立的组件目录。
lib 目录结构调整如下:
|───lib 目录:打包生成的 bundle.js 目录
| └───bundle.js // 打包生成的 bundle
| └───组件一
| └───index.js
| └───组件 n
| └───index.js
通过 webpack 多入口实现,其他配置不变,添加以下配置:
/**
* 获取 packages 下所有组件目录的名称和对应的路径, 生成所有的 entry
* @returns entry
*/
const getWebpackEntries = () => {
// ...
}
module.exports = {
// ...
entry: getWebpackEntries(), // 多入口
output: {
filename: '[name]/index.js',
path: path.resolve(__dirname, '../lib/'),
libraryTarget: 'umd',
globalObject: 'this',
umdNamedDefine: true,
},
}