最近,我准备基于 rollup 编写一个 @draculabo/alias 辅助库,并将其发布到 npm 上。为了兼容不同模块(例如 CommonJS 和 ESModule),可以使用打包器轻松地将代码分别编译成这些不同的模块格式。
刚好,rollup 3 官方版本已发布,我将使用它来尝试。
为什么不是 Webpack?
Rollup 的特点是支持 ES6 模块和代码 Tree-shaking。这些特性在 Webpack 中同样有支持。除此之外,Webpack 还支持热模块替换、代码分割、静态资源导入等更多功能。当需要开发应用时,优先选择 Webpack。但是,如果只需要打包出一个简单的 Bundle 包,而且是基于 ES6 模块开发的,则可以考虑使用 Rollup。相比于 Webpack,Rollup 有更少的功能和更简单的 API。这也是我们在打包类库时选择 Rollup 的原因。当然,我准备编写的工具包正是这样的项目。
支持打包的模块格式
目前常见的模块规范有:
IFFE:使用立即执行函数实现模块化 例:
(function(){})()
CJS:基于 CommonJS 标准的模块化
AMD:使用 Require 编写
ESM:ES 标准的模块化方案 ( ES6 标准提出 )
UMD:兼容 CJS 与 AMD、IFFE 规范
以上 Rollup 都是支持的。
使用
官方提供了一篇创建你的第一个 bundle的文章。不过英文文档阅读难度较大,而且通过命令方式+选项的方式打包不是我们想要的工程化方式。
配置文件
因此,可以通过 rollup.config.js
配置文件来打包,然后通过rollup -c
命令进行打包。以下是一个示例文件:
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs',
},
}
运行 rollup -c
命令就会将 main.js
中所引用到的 js 代码,按照 commonjs 的方式编写到 bundle.js
文件中,如下所示:
'use strict'
var foo = 'hello world!'
function main() {
console.log(foo)
}
module.exports = main
更多的情况下,需要同时打包多个模块格式的包。此时,在 output 属性中传入一个由多个输出对象组成的数组,例如:
export default {
input: 'src/main.js',
output: [
{
file: 'bundle.cjs',
format: 'cjs',
},
{
file: 'bundle.mjs',
format: 'esm',
},
],
}
便会生成 bundle.cjs
, bundle.mjs
两种不同的模块格式的文件。同时在 package.json
中,指定对应模块路径,在引入时,便会根据当前的项目环境去选择导入哪个模块。
{
"main": "bundle.cjs",
"module": "bundle.mjs"
}
结合 rollup 插件使用
更多情况下,需要配置 Rollup 插件来使用。官方插件地址是rollup/plugins。
例如,可以使用 rollup-plugin-esbuild 插件来加快打包速度,同时可以借助 @rollup/plugin-babel 使用 babel,将代码转换成兼容性更强的。
以下是 rollup + 插件的配置示例,来源于antfu/utils/rollup.config.js,同时也是我工具包的配置。
import esbuild from 'rollup-plugin-esbuild'
import dts from 'rollup-plugin-dts'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import alias from '@rollup/plugin-alias'
const entries = ['src/index.ts']
const plugins = [
alias({
entries: [{ find: /^node:(.+)$/, replacement: '$1' }],
}),
resolve({
preferBuiltins: true,
}),
json(),
commonjs(),
esbuild({
target: 'node14',
}),
]
export default [
...entries.map(input => ({
input,
output: [
{
file: input.replace('src/', 'dist/').replace('.ts', '.mjs'),
format: 'esm',
},
{
file: input.replace('src/', 'dist/').replace('.ts', '.cjs'),
format: 'cjs',
},
],
external: [],
plugins,
})),
...entries.map(input => ({
input,
output: {
file: input.replace('src/', '').replace('.ts', '.d.ts'),
format: 'esm',
},
external: [],
plugins: [dts({ respectExternal: true })],
})),
]
以下是对应的 npm 安装命令
pnpm i -D rollup @rollup/plugin-alias @rollup/plugin-commonjs @rollup/plugin-json @rollup/plugin-node-resolve rollup-plugin-esbuild rollup-plugin-dts
更多 Rollup 的使用信息,可以参见官方文档以及其他使用 Rollup 打包的开源项目。
类似工具
除了 Rollup 之外,还有其他打包工具,例如Webpack.js、esbuild、Parcel.js。
不过,对于打包类库而言,并不要求过于强大的性能,只需要一个相对简单的配置就足以胜任,而 Rollup 正是这样的打包工具。