本文同步自我的博客 JoeRay61
简介
rollup 是 JavaScript 模块打包工具,能够将多个具有引用依赖关系的脚本文件打包成一个文件,并且能够做到只引入使用到的代码,如果使用 ES6 的模块系统的话。举个简单的栗子:
// foo.js
export let a = 'hello world!';
export let b = 'hello rollup!';
// main.js
import {a} from './foo';
export default () => {
console.log(`the string is ${a}`);
}
以main.js
作为程序入口,使用rollup
打包后的代码是
// bundle.js
'use strict';
var a = 'hello world!';
var main = (function () {
console.log('the string is ' + a);
});
module.exports = main;
可以看到,foo.js
和main.js
被打包到bundle.js
中,并且只引入了foo.js
中使用到的export let a = 'hello world!';
安装
局部安装
$ npm i rollup
全局安装(可能需要sudo
)
$ npm i -g rollup
使用
CLI
$ rollup
rollup 版本 0.41.6
=====================================
用法: rollup [选项] <入口文件>
基础选项:
-v, --version 显示版本号
-h, --help 显示帮助信息
-c, --config 使用这个配置文件 (如果使用了该参数,但是并没有指定具体的配置文
p.config.js`)
-w, --watch 观察要打包文件的变动,并且在有变动时重新打包
-i, --input 输入 (另一种指定<入口文件>的方式)
-o, --output <output> 输出 (如果缺省,则输出到控制台)
-f, --format [es] 输出类型 (amd, cjs, es, iife, umd)
-e, --external 用逗号分隔的不需要打包的模块 ID 列表
-g, --globals 用逗号分隔的`module ID:Global`键值对
任何在这里定义的模块 ID 都会被加入到 external 选项中
-n, --name UMD 输出的命名
-u, --id AMD 模块的 ID (默认是匿名的)
-m, --sourcemap 生成 sourcemap (`-m inline`用于生成内联map)
--no-strict 不要在生成的模块中声明`use strict;`
--no-indent 不要缩进结果
--environment <values> 传给配置文件的设置 (见示例)
--no-conflict 为 UMD 模块生成一个 noConflict 方法
--silent 不要打印警告
--intro 需要插入到包顶部的内容(在 amd/umd/iife 包装函数的内部)
--outro 需要插入到包底部的内容(在 amd/umd/iife 包装函数的内部)
--banner 需要插入到包顶部的内容(在 amd/umd/iife 包装函数的外部)
--footer 需要插入到包底部的内容(在 amd/umd/iife 包装函数的外部)
示例:
# 在配置文件中使用设置
rollup -c
# 在配置文件中, process.env.INCLUDE_DEPS === 'true'
# 并且 process.env.BUILD === 'production'
rollup -c --environment INCLUDE_DEPS,BUILD:production
# 从 src/main.js 创建 CommonJS 类型的包 bundle.js
rollup --format=cjs --output=bundle.js -- src/main.js
# 创建一个使用`window.jQuery`和`window._`这两个全局变量的自执行的函数
rollup -f iife --globals jquery:jQuery,lodash:_ \
-i src/app.js -o build/app.js -m build/app.js.map
注意:
* 当输出到控制台时,只允许使用内联 sourcemaps
访问 https://github.com/rollup/rollup/wiki 获取更多信息
配置文件
跟 webpack 一样,rollup 也可以使用配置文件,通过 cli 的-c
参数来指定配置文件,默认为当前目录下的rollup.config.js
。
使用配置文件有几点好处:
重复编译时,不需要重复输入大段的 CLI 配置参数
配置文件中我们可以进行编程,这样能够完成一些纯靠 CLI 参数无法完成的配置
配置文件需要输出一个配置对象
// rollup.config.js
export default {
// write config key: value pair here
};
常用的配置项其实跟 CLI 大同小异,具体如下:
entry
: String,入口文件路径format
: String,输出类型 (amd
,cjs
,es
,iife
,umd
)plugins
: Array,插件声明external
: Array,不需要打包的文件dest
: String,输出的打包文件sourceMap
: Boolean,是否要支持 sourcemap
插件
rollup 的插件一般以 npm 包的形式引入,在配置文件中 plugins 里面声明。下面我介绍几个常用的 rollup 插件
rollup-plugin-json
需要加载 json 文件的数据时,可以通过rollup-plugin-json
这个插件
rollup-plugin-node-resolve
这个插件可以让 rollup 更加智能地找到各个需要打包的文件路径
rollup-plugin-commonjs
目前大多数的 npm 包还是以 CommonJS 模块的形式对外 export,rollup 本身无法解析他们,需要用rollup-plugin-commonjs
先把他们转换成 ES6 的模块
rollup-plugin-babel
熟悉 babel 的人大概已经猜到了,这个插件能让 rollup 具有 babel 的能力,可以用来转换 ES6 的代码,在使用前需要先配置.babelrc',要注意的是不能用 babel 转换 ES6 的模块,因为 rollup 的打包是依赖于 ES6 模块的。
.babelrc`配置如下:
{
"presets": [
["latest", {
"es2015": {
"modules": false
}
}]
]
}
API
rollup 可以作为一个包引入到 js 程序中
var rollup = require('rollup');
他提供了几个 API:
rollup.rollup(options)
根据 options 选项执行打包过程,返回一个 Promise 对象,该对象在调用 resolve 时会传入打包后的bundle
对象
bundle.generate(options)
根据 options 生成代码,返回一个{code, sourcemap}
对象
bundle.write(options)
与bundle.generate
类似,但是可以直接将编译结果写入到文件中。
以上只对 API 的功能做了简要介绍,具体可以参考官方wiki
Tree-Shaking
rollup 中的 Tree-Shaking 又叫live code inclusion
,能够做到只引入使用的代码,减少打包后的文件大小,这与我们常说的DCE( Dead Code Elimination)
目的一致,但是做法相反,DCE 的思路是提出不用的代码,从语义上来说,DCE 更符合 Tree-Shaking 的表述(想象熊孩子在摇晃一棵树,树上一些枯死的枝芽都被晃掉下来了)。
其实 rollup 的 Tree-Shaking 也只是处理了顶层的 AST,所以 rollup 处理后的代码仍然可能存在冗余,另外,Tree-Shaking 也不是代码压缩,所以也需要在这之后使用代码压缩工具进一步缩小文件大小。
Tree-Shaking的实现主要归功于 ES6 的模块,ES6 的模块是静态的 import 和 export,基于这个特性才能够进行模块的静态分析,这是在动态的 CommonJS 和 AMD 模块里无法做到的。这也是为什么 rollup 要求使用 ES6 模块的原因。
推荐大家阅读一下 Rich Harris 的这篇文章:Tree-shaking versus dead code elimination(需要翻墙)
rollup vs webpack
同样是打包工具,我们自然要将 rollup 和 webpack 比较一番,以下是我认为的几点区别,不一定对,欢迎留言讨论
rollup 一般用于 JavaScript 库的开发,而 webpack 一般用于 web 应用的开发
rollup 希望打包后的代码还是像人写的代码,而不是机器生成的代码,所以 rollup 不会给每个模块包上一层 function,也不会在打包后的文件顶部加上一个模块加载器,而 webpack 相反
基于第 2 点,rollup 打包后的文件比 webpack 打包后的文件更小