打包组件库,首先想到就是用Rollup,感觉 library 打包用 Rollup,更小的打包体积、更多选择的输入文件格式,比如ES6 module, CommonJS等。
关于Rollup 和 Webpack 打包性能优化对比可参考这篇文章 Tree-Shaking性能优化实践 – 原理篇
本文主要记录的是遇到了rollup打包Vue2.x组件库的JSX无法识别的问题。Rollup的一些基础打包操作,网上都有很多非常好的讲解,可参考:rollup-完全入门指南
Rollup英文官方文档,英文的文档信息更新及时。
组件库Vue2.x需要的基础配置
-
组件库基础框架版本
vue 2.6.11 node 14.4.0 babel 7.14.0 复制代码
-
组件库的项目结构参考的是element-ui结构。
安装rollup
npm install --global rollup 复制代码
组件库的开发肯定少不了引入模块、es6等,因此需要用插件(Plugins) 在打包的过程中更改Rollup的一些行为。
-
安装插件
由于 Node 模块使用的是 CommonJS,它并不被 Rollup 兼容因此不能直接使用。因此这两插件主要是解决该问题。
npm i -D @rollup/plugin-node-resolve @rollup/plugin-commonjs 复制代码
rollup-plugin-vue插件需指定版本,@5.1.9对应的是vue2.x,@6.0.0以上对应的是vue3.x
npm i -D rollup-plugin-vue@latest 复制代码
rollup 代码压缩插件
rollup-plugin-terser 复制代码
rollup-plugin-babel 该插件就是踩的关键的坑了。开源库提示,rollup-plugin-babel此插件迁移到了@rollup/plugin-babel,于是更新到了@rollup/plugin-babel调试,没使用jsx语法的打包没问题,使用了jsx语法的都无法识别,改为rollup-plugin-babel后则正常了。
rollup-plugin-babel插件需指定版本,babel7.x
npm install --save-dev rollup-plugin-babel@latest 复制代码
babel6.x
npm install --save-dev rollup-plugin-babel@3 复制代码
rollup-plugin-babel插件需要 babel 支持
npm install --save-dev @babel/core @babel/cli @babel/preset-env 复制代码
vue2.0 JSX 需要 babel-plugin-transform-vue-jsx支持
npm install\ babel-plugin-syntax-jsx\ babel-plugin-transform-vue-jsx\ babel-helper-vue-jsx-merge-props\ babel-preset-env\ --save-dev 复制代码
配置文件内容如下:
- .babelrc
{
"presets": [
"@vue/app",
[
"@babel/preset-env",
{
"modules": false
}
]
],
"ignore": ["node_modules/**"],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-proposal-object-rest-spread"
]
}
复制代码
- rollup.config.js
import {camelCase} from 'lodash'
import babel from 'rollup-plugin-babel'
//import { babel } from '@rollup/plugin-babel'
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import resolve from '@rollup/plugin-node-resolve'
import replace from '@rollup/plugin-replace' // 打包时替换代码中的指定字符串
import vue from 'rollup-plugin-vue'
import postcss from 'rollup-plugin-postcss'
import filesize from 'rollup-plugin-filesize' // 显示打包文件大小
import {terser} from 'rollup-plugin-terser' // 代码压缩
import pack from './package.json'
const projectName = pack.name
const sass = require('node-sass')
const path = require('path')
// compute globals from dependencies
const globals =
pack.dependencies &&
Object.assign(
{},
...Object.keys(pack.dependencies).map((key) => ({
[key]: camelCase(key),
}))
)
const builds = {
// (CommonJS). Used by bundlers e.g. Webpack & Browserify
cjs: {
entry: 'src/index.js',
dest: `dist/${projectName}.common.js`,
format: 'cjs',
},
// (ES Modules). Used by bundlers that support ES Modules,
// e.g. Rollup & Webpack 2
esm: {
entry: 'src/index.js',
dest: `dist/${projectName}.esm.js`,
format: 'es',
},
// build (Browser)
'umd-dev': {
entry: 'src/index.umd.js',
dest: `dist/${projectName}.js`,
format: 'umd',
env: 'development',
},
// production build (Browser)
'umd-prod': {
entry: 'src/index.umd.js',
dest: `dist/${projectName}.min.js`,
format: 'umd',
env: 'production',
},
}
const processSass = function(context) {
return new Promise((resolve, reject) => {
sass.render(
{
file: context,
},
function(err, result) {
if (!err) {
resolve(result)
} else {
reject(err)
}
}
)
})
}
function genConfig(name) {
const opts = builds[name]
const config = {
input: opts.entry,
external: (id) => pack.dependencies && pack.dependencies[id], // exclude dependencies from build
plugins: [
vue({compileTemplate: true, css: true}),
babel({
runtimeHelpers: true,
exclude: 'node_modules/**',
}),
resolve({
browser: true,
preferBuiltins: false,
extensions: ['.js', '.json', '.jsx', '.vue'],
}),
commonjs(),
json(),
postcss({
minimize: true,
extensions: ['.css', '.scss'],
process: processSass,
extract: path.resolve(`dist/style/${projectName}.css`)
}),
filesize(),
].concat(opts.plugins || []),
output: {
exports: 'named',
file: opts.dest,
format: opts.format,
// define globals in window from external dependencies
globals,
name: opts.moduleName || projectName,
},
}
if (opts.env) {
config.plugins.push(
replace({
'process.env.NODE_ENV': JSON.stringify(opts.env),
})
)
// minify on production targets
if (opts.env === 'production') {
config.plugins.push(terser())
}
}
Object.defineProperty(config, '_name', {
enumerable: false,
value: name,
})
return config
}
const target = process.env.TARGET || 'umd-prod'
module.exports = genConfig(target)
复制代码
- 配置scripts脚本
在根目录的 package.json 中配置 build 脚本
"scripts": {
"build-lib": "npm run build:cjs && npm run build:es && npm run build:umd:dev && npm run build:umd:prod",
"build:cjs": "rollup -c --environment TARGET:cjs",
"build:es": "rollup -c --environment TARGET:esm",
"build:umd:dev": "rollup -c --environment TARGET:umd-dev",
"build:umd:prod": "rollup -c --environment TARGET:umd-prod",
"pub": "npm run build-lib && npm publish --access public"
}
复制代码
存在的问题
@rollup/plugin-babel 替换 rollup-plugin-babel 待解决中,欢迎在评论区讨论。