使用 Rollup 构建你的 Library
Rollup, 和 Webpack, Parcel 都是模块打包工具(module bundler tool), 但是侧重点不同, 我们要聊的 Rollup 更加适合用于构建 Library, 而 Webpack, Precel 更加适合开发 Application.
希望通过本篇文章, 对大家构建 Library 有一定的工程上的启发.
什么是 Rollup
简单而言, Rollup 是一个模块打包工具, 可以将我们按照 ESM (ES2015 Module) 规范编写的源码构建输出如下格式:
- IIFE: 自执行函数, 可通过
<script>
标签加载 - AMD: 浏览器端的模块规范, 可通过
RequireJS
可加载 - CommonJS: Node 默认的模块规范, 可通过
Webpack
加载 - UMD: 兼容 IIFE, AMD, CJS 三种模块规范
- ESM: ES2015 Module 规范, 可用
Webpack
,Rollup
加载
大多数的 Library 也是选择使用 Rollup 构建, 比如: React, Vue, Angular, D3, Moment, Redux…
借助于 Rollup 的插件体系, 我们也可以处理 css, images, font 等资源, 但是 Rollup 不支持代码拆分(Code Splitting)和运行时态加载(Dynamic Import) 特性, 所以较少的应用于 Application 开发.
为什么选择 Rollup
- Tree Shaking: 自动移除未使用的代码, 输出更小的文件
- Scope Hoisting: 所有模块构建在一个函数内, 执行效率更高
- Config 文件支持通过 ESM 模块格式书写
- 可以一次输出多种格式:
- 不用的模块规范: IIFE, AMD, CJS, UMD, ESM
- Development 与 production 版本:
.js
,.min.js
- 文档精简
使用教程
安装教程就不列举了, 为大家提供一个 starter 模板: rollup-starter-kit. 主要说下开发一个 Library 我们需要哪些基础插件以及他们的配置.
基础插件
- rollup-plugin-alias: 提供 modules 名称的 alias 和 reslove 功能.
- rollup-plugin-babel: 提供 Babel 能力, 需要安装和配置 Babel (这部分知识不在本文涉及)
- rollup-plugin-eslint: 提供 ESLint 能力, 需要安装和配置 ESLint (这部分知识不在本文涉及)
- rollup-plugin-node-resolve: 解析 node_modules 中的模块
- rollup-plugin-commonjs: 转换 CJS -> ESM, 通常配合上面一个插件使用
- rollup-plugin-replace: 类比 Webpack 的 DefinePlugin , 可在源码中通过
process.env.NODE_ENV
用于构建区分 Development 与 Production 环境. - rollup-plugin-filesize: 显示 bundle 文件大小
- rollup-plugin-uglify: 压缩 bundle 文件
- rollup-plugin-serve: 类比 webpack-dev-server, 提供静态服务器能力
Rollup 配置
构建命令我们通常还会使用 cross-env 区分 NODE_ENV
, npm scripts
是这样:
{
"clean": "rimraf dist",
"start": "yarn run clean && cross-env NODE_ENV=development rollup -w -c scripts/rollup.config.dev.js",
"build": "yarn run clean && cross-env NODE_ENV=production rollup -c scripts/rollup.config.prod.js",
}
Rollup 的配置文件建议拆分为多份, 比如:
- rollup.base.js
- rollup.dev.js
- rollup.prod.js
rollup.base.js
中, 我们维护通用的配置:
import alias from 'rollup-plugin-alias';
import eslint from 'rollup-plugin-eslint';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import replace from 'rollup-plugin-replace';
export default {
input: 'src/main.js',
plugins: [
alias({
resolve: ['.js']
}),
replace({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
resolve(),
commonjs({
// non-CommonJS modules will be ignored, but you can also
// specifically include/exclude files
include: 'node_modules/**'
}),
eslint({
include: ['src/**/*.js']
}),
babel({
runtimeHelpers: true,
exclude: 'node_modules/**' // only transpile our source code
})
]
}
开发环境配置
由于是开发 Library, 建议大家编写单元测试, 示例工程我们使用 Jest 作为测试框架. 开发过程中还可通过rollup-plugin-serve
提供静态资源访问:
plugins: [
...baseConfig.plugins,
serve({
port: 8080,
contentBase: ['']
})
]
生产环境的配置
构建生产版本时候, 我们一般期待结果有如下特性:
- 去除开发环境调试信息
- 一个 entry 文件, 多个 output 版本
- 包含文件头注释, 可以是版本, 作者或开源协议声明
- 文本混淆与压缩
对应于我们的配置文件如下:
import filesize from 'rollup-plugin-filesize';
import uglify from 'rollup-plugin-uglify';
import { minify } from 'uglify-es';
import baseConfig from './rollup.config.base';
import { name, version, author } from '../package.json';
// banner
const banner =
`${'/*!\n' + ' * '}${name}.js v${version}\n` +
` * (c) 2018-${new Date().getFullYear()} ${author}\n` +
` * Released under the MIT License.\n` +
` */`;
// 支持输出 []
export default [
// .js, .cjs.js, .esm.js
{
...baseConfig,
output: [
// umd development version with sourcemap
{
file: `dist/${name}.js`,
format: 'umd',
name,
banner,
sourcemap: true
},
// cjs and esm version
{
file: `dist/${name}.cjs.js`,
format: 'cjs',
banner
},
// cjs and esm version
{
file: `dist/${name}.esm.js`,
format: 'es',
banner
}
],
plugins: [...baseConfig.plugins, filesize()]
},
// .min.js
{
...baseConfig,
output: [
// umd with compress version
{
file: `dist/${name}.min.js`,
format: 'umd',
name,
banner
}
],
plugins: [
...baseConfig.plugins,
uglify(
{
compress: {
drop_console: true
}
},
minify
),
filesize()
]
}
];
Npm 包发布的一些建议
- 通过 standard-version 工具管理发布的 tag 和 CHANGELOG.md
- 包的名称带上命名空间:
@xx/xx
- 提供接口声明文件:
xx.d.ts
, 可通过 package.json 中typings
指定 - package.json 中
modules
指定 ESM 模块,webpack
,rollup
会优先获取 ESM 模块 - package.json 中
main
指定 CJS 模块
写在最后
文章主要讲解一些配置和实践规范, 具体效果可参见示例代码: rollup-starter-kit, 欢迎大家提 Issue 交流.
编辑于 2018-04-14 12:47