2

本文同步自我的博客 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.jsmain.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 比较一番,以下是我认为的几点区别,不一定对,欢迎留言讨论

  1. rollup 一般用于 JavaScript 库的开发,而 webpack 一般用于 web 应用的开发

  2. rollup 希望打包后的代码还是像人写的代码,而不是机器生成的代码,所以 rollup 不会给每个模块包上一层 function,也不会在打包后的文件顶部加上一个模块加载器,而 webpack 相反

  3. 基于第 2 点,rollup 打包后的文件比 webpack 打包后的文件更小


JoeRay61
2.3k 声望182 粉丝