Menu
rollup.js

介绍

概述

Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是以前的特殊解决方案,如 CommonJS 和 AMD。

快速入门指南

使用 npm install --global rollup 进行安装。Rollup 可以通过命令行接口(command line interface)配合可选配置文件(optional configuration file)来调用,或者可以通过 JavaScript API来调用。运行 rollup --help 可以查看可用的选项和参数。启动项目模板演示了常用的配置选项,并且用户指南也提供了更详尽的说明。

命令

这些命令假设应用程序入口起点的名称为 main.js,并且你想要所有 import 的依赖(all imports)都编译到一个名为 bundle.js 的单个文件中。

对于浏览器:

# compile to a <script> containing a self-executing function
$ rollup main.js --format iife --output bundle.js

对于 Node.js:

# compile to a CommonJS module
$ rollup main.js --format cjs --output bundle.js

对于浏览器和 Node.js:

# UMD format requires a bundle name
$ rollup main.js --format umd --name "myBundle" --output bundle.js

为什么

如果你将项目拆分成小的单独文件中,这样开发软件通常会很简单,因为这通常会消除无法预知的相互影响(remove unexpected interaction),以及显著降低了所要解决的问题的复杂度(complexity of the problem),并且可以在项目最初时,就简洁地编写小的项目(不一定是标准答案)。不幸的是,JavaScript 以往并没有将此功能作为语言的核心功能。

Tree Shaking

除了使用 ES6 模块之外,Rollup 还静态分析代码中的 import,并将排除任何未实际使用的代码。这允许您架构于现有工具和模块之上,而不会增加额外的依赖或使项目的大小膨胀。

例如,在使用 CommonJS 时,必须导入(import)完整的工具(tool)或库(library)对象

// 使用 CommonJS 导入(import)完整的 utils 对象
var utils = require( 'utils' );
var query = 'Rollup';
// 使用 utils 对象的 ajax 方法
utils.ajax( 'https://api.example.com?search=' + query ).then( handleResponse );

但是在使用 ES6 模块时,无需导入整个 utils 对象,我们可以只导入(import)我们所需的 ajax 函数:

// 使用 ES6 import 语句导入(import) ajax 函数
import { ajax } from 'utils';
var query = 'Rollup';
// 调用 ajax 函数
ajax( 'https://api.example.com?search=' + query ).then( handleResponse );

因为 Rollup 只引入最基本最精简代码,所以可以生成轻量、快速,以及低复杂度的 library 和应用程序。因为这种基于显式的 importexport 语句的方式,它远比「在编译后的输出代码中,简单地运行自动 minifier 检测未使用的变量」更有效。

ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码。ES6 模块最终还是要由浏览器原生实现,但当前 Rollup 可以使你提前体验。

兼容性

导入 CommonJS

Rollup 可以通过插件导入已存在的 CommonJS 模块。

发布 ES6 模块

为了确保你的 ES6 模块可以直接与「运行在 CommonJS(例如 Node.js 和 webpack)中的工具(tool)」使用,你可以使用 Rollup 编译为 UMD 或 CommonJS 格式,然后在 package.json 文件的 main 属性中指向当前编译的版本。如果你的 package.json 也具有 module 字段,像 Rollup 和 webpack 2 这样的 ES6 感知工具(ES6-aware tools)将会直接导入 ES6 模块版本

参考链接


原文:https://rollupjs.org/#introduction

创建你的第一个文件束(bundle)

在我们开始前,你将需要安装 Node.js 那样你才可以使用 npm。你也将会需要知道如何在你的机器上使用 command line

最容易的办法去使用 Rollup 是通过命令行界面 (or CLI). 现在,我们将全局安装它(稍后我们将会学习如何在你的本地项目安装,因而令你的构建流程是可移植的,但现在可以暂时不要担忧这点)。 在命令行中输入:

npm install rollup --global # 或简写 `npm i rollup -g`

你现在可以运行 rollup 命令。来试试!

rollup

因为没有参数被传入,Rollup 输出使用指引。这跟运行 rollup --help, or rollup -h 如出一辙。

让我们新建一个简单的项目:

mkdir -p my-rollup-project/src
cd my-rollup-project

首先,我们需要一个 入口文件(entry point). 粘贴下面这段代码到一个新的文件里,名为 src/main.js:

// src/main.js
import foo from './foo.js';
export default function () {
  console.log(foo);
}

然后,让我们创建 foo.js 文件模块,我们的入口文件会引入:

// src/foo.js
export default 'hello world!';

现在,我们已经准备好要创建一个文件束了:

rollup src/main.js --format cjs

--format 参数指定我们正在创建的文件束类型 — 在这个事例中,CommonJS (能在 Node.js 中运行).因为我们没有指定输出文件,它的内容将会被直接输出到 stdout

'use strict';

var foo = 'hello world!';

var main = function () {
  console.log(foo);
};

module.exports = main;

你可以像这样将文件束另存为文件:

rollup src/main.js --format cjs --output bundle.js
# or `rollup main.js -f cjs -o bundle.js`

(你也可以用 rollup src/main.js > bundle.js, 但后面我们将会看到,如果你会生成 sourcemaps,这种办法将不太灵活。)

尝试跑下面代码:

node
> var myBundle = require('./bundle.js');
> myBundle();
'hello world!'

恭喜你!你已经使用 Rollup创建了你的第一个文件束。


原文:https://rollupjs.org/#creating-your-first-bundle

使用配置文件

到目前为止,都进展顺利, 但随着我们添加越来越多的参数,使用命令行去输入这些参数变得越来越是一件麻烦事。

为了避免重复,我们可以创建一个文件包含所有我们需要的参数。这个配置文件是使用 JavaScript 写的,并且被单纯的命令行界面要更灵活。

在项目根目录创建一个名为 rollup.config.js 的文件, 同时添加下面的代码:

// rollup.config.js
export default {
  entry: 'src/main.js',
  format: 'cjs',
  dest: 'bundle.js' // 相当于 --output
};

为了使用配置文件,我们使用 --config or -c 标记:

rm bundle.js # 那我们可以检查命令是否生效!
rollup -c

你可以用等价的命令行参数去重写任何在配置文件里的参数:

rollup -c -o bundle-2.js # --output 等价于 dest

(注意 Rollup 自行去处理配置文件,这也是为什么我们可以使用 export default 语法 – 代码并没有被 Babel 或其它类似的工具转译, 所以你只可以使用你电脑上运行的 Node.js 版本所支持的那些 ES2015 特性。)

如果你喜欢,你可以指写一个与默认 rollup.config.js 不同的配置文件:

rollup --config rollup.config.dev.js
rollup --config rollup.config.prod.js

原文:https://rollupjs.org/#using-config-files

npm run build

许多 JavaScript 项目都遵循一个简单的约定:输入 npm run build 执行任何项目使用的构建系统。这点非常有用是因为它意味着有人想帮着贡献你的项目,他可以直接投身进源码中,而不需要知晓任何与之绑定的基础设施(像Rollup, 或 Webpack, 或 Gulp, 或一些更为难懂的)。他们甚至不需要全局安装它,正如我们在第一部份所做的一样。

设置你自己的 npm run build 脚本是非常好并且是直截了当的。

创建立一个 package.json 文件

一个 package.json 包含关于你项目的重要信息,包括它的名称、版本、许可证和依赖。(实际上,你不可以发布一个不包括 package.json 的程序包 - 但你仍然应该有一个这样的文件如果你构建的是一个应用而非一个库)。

最容易的方式去创建一个项目是在项文件夹里去执行 npm init 及跟着提示去做。

打开 package.json 并找到(创建) scripts 部份, 添加 build 键值:

{
  ...,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rollup -c"
  },
  ...
}

(这里假设你已经有一个 rollup.config.js 文件在项目文件夹里了)。

本地安装Rollup

直到现在,我们已经使用了全局安装的 Rollup. 但使用 本地 安装的会更好,因为这样任何人克隆你的项目和运行 npm install 将会得到一个兼容的版本。

执行以下的命令...

npm install --save-dev rollup # or `npm i -D rollup`

...你会留意到 devDependencies 部份被添加到你项目的 package.json 文件中:

{
  ...,
  "devDependencies": {
    "rollup": "^0.41.4"
  },
  ...
}

你所有的 npm run 脚本都将会寻找本地安装的命令,如 rollup 若它们存在的话。

尝试运行脚本:

npm run build

当文件更新,用npm run dev 重新构建

通过安装 rollup-watch, 你可以创建一个脚本,当它的源文件改变的时候,它会自动重新构建:

npm install --save-dev rollup-watch
{
  ...,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rollup -c",
    "dev": "rollup -c -w"
  },
  ...
}

命令 rollup -c -w (是 rollup --config --watch 的简写) 让 Rollup 在监视模式下运行。


原文:https://rollupjs.org/#npm-run-build

插件的开始

到目前为止,我们已经从一个入口点和通过相对路径导入的模块创建了一个简单的bundle。当您需要构建更为复杂的bundle时,您通常需要更多的灵活性 - 例如导入使用npm来安装的模块、使用Babel编译代码、使用JSON文件等等。

针对以上原因,我们使用了 插件,它可以在打包过程的关键点改变Rollup的行为。在the Rollup wiki上维护了可用插件的列表。

使用插件

在本教程中,我们将使用rollup-plugin-json作为例子,它允许Rollup从JSON文件导入数据。

首先安装rollup-plugin-json作为开发依赖:

npm install --save-dev rollup-plugin-json

(我们使用--save-dev而不是--save,因为我们的代码实际上在运行时不依赖于插件, - 只有当我们构建打包时才会使用到。)

然后更新您的src/main.js文件,以便它从您的package.json导入而不是从src/foo.js导入:

// src/main.js
import { version } from '../package.json';

export default function () {
  console.log('version ' + version);
}

其次编辑您的rollup.config.js文件以包含JSON插件:

// rollup.config.js
import json from 'rollup-plugin-json';

export default {
  entry: 'src/main.js',
  format: 'cjs',
  plugins: [ json() ],
  dest: 'bundle.js'
};

最后通过命令npm run build来运行Rollup。结果应该是这样子的:

'use strict';

var version = "1.0.0";

var main = function () {
  console.log('version ' + version);
};

module.exports = main;

(请注意,只有我们实际需要的数据才会被导入 - namedevDependencies以及package.json的其他部分是被忽略的。哪是因为tree-shaking在起作用!)


原文:https://rollupjs.org/#getting-started-with-plugins

使用 Rollup 和 npm 程序包

某些时候,很可能你的项目会依赖于 npm 安装到 node_modules 文件夹中的程序包。跟其它打包工具如 Webpack 和 Browserify 不同,Rollup 不知道如何去开箱即用地处理这些依赖 - 我们需要添加一些配置。

让我们添加一个简单的依赖,叫 the-answer, 它输出对生活、宇宙及其它一切的答案:

npm install --save the-answer # or `npm i -S the-answer`

注意我们这次使用 --save,因为这样它会被保存到 package.json 的 dependencies 部份。

如果我们更新 src/main.js 文件...

// src/main.js
import answer from 'the-answer';

export default function () {
  console.log('the answer is ' + answer);
}

...运行 Rollup...

npm run build

...我们会看到下面的警告:

⚠️ 'the-answer' is imported by src/main.js, but could not be resolved – treating it as an external dependency
⚠️ 'the-answer' 被 src/main.js 引用,但不知道如何去解析 - 把它看作是外部的以来

生成的 bundle.js 在 Node.js 中仍然能运行,因为 import 声音被编译为 CommonJS 的 require 语句,但 the-answer 并没有 被打包到文件束中。为此,我们需要一个插件。

rollup-plugin-node-resolve

rollup-plugin-node-resolve 插件指导 Rollup 如果去寻找外部的模块。请安装...

npm install --save-dev rollup-plugin-node-resolve

...将它添加到你的配置文件中:

// rollup.config.js
import resolve from 'rollup-plugin-node-resolve';

export default {
  entry: 'src/main.js',
  format: 'cjs',
  plugins: [ resolve() ],
  dest: 'bundle.js'
};

这次,当你运行 npm run build, 再没有警告输出 - 文件束包含了引用的模块。

rollup-plugin-commonjs

一些库输出 ES6 模块,你可以照原来的样子引用 - the-answer 正是这样的一个模块。但当下,大部份 npm 的程序包都被输出为 CommonJS 模块。直到它改变,在 Rollup 处理它们之前,我们都需要将 CommonJS 转成 ES2015。

rollup-plugin-commonjs 插件就正好来处理这件事。

注意 rollup-plugin-commonjs 应该在其它插件变换你的模块之前使用 - 这是为了避免其它插件做了一些改变,而这改变会破坏了 CommonJS 的检测。

Peer dependencies

比方说,你正在开发一个有 peer dependency 的库,例如 React 或者 Lodash。如果你像上面描述的那样设置 externals,你的 rollup 会打包 所有的 引用:

import answer from 'the-answer';
import _ from 'lodash';

你可以很好地调整哪些需要被打包,哪些应该看作外部引用 (external)。在这个例子里,我们把 lodash 看作外部引用(external),而不是 ths-answer。这里是配置文件:

// rollup.config.js
import resolve from 'rollup-plugin-node-resolve';

export default {
  entry: 'src/main.js',
  format: 'cjs',
  plugins: [resolve({
    // 给 resolve 插件传入自定配置
    customResolveOptions: {
      moduleDirectory: 'node_modules'
    }
  })],
  // 指明哪个模块被看作外部引用(external)
  external: ['lodash'],
  dest: 'bundle.js'
};

看, lodash 现在被看成外部引用(external),而没有被打包进你的库中。

external 参数接受一个模块名称的数组,或者一个函数,这个函数接收模块名,如果它被看作外部引用(external),会返回 true。例如:

export default {
  // ...
  external: id => /lodash/.test(id)
}

你可能会使用这个形式的插件 babel-plugin-lodash 去择优挑选 lodash 模块。这个请况下, Babel 会将你的引用语句转化成如下代码:

import _merge from 'lodash/merge';

如果 external 是数组形式,它不会处理通配符(*),所以这种引用只有在函数形式的时候,才会被看作外部引用(external)。


原文:https://rollupjs.org/#using-rollup-with-npm

使用 Rollup 和 Babel

许多开发者在他们的项目中使用 Babel,因此他们可以用上那些未被浏览器和 Node.js 支持的未来的 JavaScript 特性。

最容易的办法去同时使用 Babel 和 Rollup 是使用 rollup-plugin-babel. 安装它:

npm i -D rollup-plugin-babel

将它添加到 rollup.config.js 里面:

// rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';

export default {
  entry: 'src/main.js',
  format: 'cjs',
  plugins: [
    resolve(),
    babel({
      exclude: 'node_modules/**' // 仅仅转译我们的源码
    })
  ],
  dest: 'bundle.js'
};

在 Babel 将编译你的代码前,它需要被配置。新建一个文件 src/.babelrc

{
  "presets": [
    ["latest", {
      "es2015": {
        "modules": false
      }
    }]
  ],
  "plugins": ["external-helpers"]
}

这里有几个关于配置的与不常不同的事情。首先我们设置 "modules": false,否则 Babel 会在 Rollup 有机会做处理之前,将我们的模块转成 CommonJS,导致 Rollup 的一些处理失败。

第二,我们使用 external-helpers 插件,它允许 Rollup 在文件束前仅引用一次任何的 'helpers' 函数,而不是在每个使用这些 'helpers' 的模块里都引入一遍(一般是默认行为)。

第三,我们将 .babelrc 文件放到 src 目录下,而非项目根目录。这允许我们可以有另一个 .babelrc 文件给一些别的操作,像测试,如果我们真的在后面需要的话 - 通常给不同的任务做不同的配置会更好。

现在,我们运行 rollup 前,我们需要安装 latest preset 和 extternal-helpers 插件:

npm i -D babel-preset-latest babel-plugin-external-helpers

现在运行 Rollup 会创建一个文件束...除了我们并没有使用任何 ES2015 的特性。让我们改一下,编辑 src/main.js:

// src/main.js
import answer from 'the-answer';

export default () => {
  console.log(`the answer is ${answer}`);
}

使用 npm run build 运行 Rollup, 同时检查一下文件束:

'use strict';

var index = 42;

var main = (function () {
  console.log('the answer is ' + index);
});

module.exports = main;

原文:https://rollupjs.org/#using-rollup-with-babel

Sourcemaps

Sourcemaps 可以通过在命令行界面中添加 --sourcemap 参数被启用,或者在你的配置文件中添加 sourceMap: true

export default {
  entry: 'src/main.js',
  format: 'umd',
  dest: 'bundle.js',
  sourceMap: true
};

原文:https://rollupjs.org/#sourcemaps

常见问题

什么是 'tree-shaking'?

Tree-shaking 亦称作 'live code inclusion',是一个只包含有被使用的代码的过程。这个过程类似于无用代码去除,但会更为高效。请阅读更多关于这个词语的来源: Tree-shaking vs Dead-Code Elimination

为什么 ES2015 模块比 AMD 和 CommonJS 更好?

ES2015 模块是官方的标准,而已将会很快应用到浏览器和Node.js中。标准允许静态分析,这使得一些优化,如 tree-shaking 能被启用,以及它还有一些更先进的特性,如循环引用和动态绑定。

谁制作了 Rollup 的 Logo。太可爱了!

我就知道! 是Julian Lloyd.制作的。


原文:https://rollupjs.org/#faqs

与其它工具的比较

即将揭晓...


原文:https://rollupjs.org/#comparison

使用 Rollup 和 Gulp

Rollup 返回 promise 对象,gulp 能够识别,因此整合起来非常容易。

语法跟配置文件很想似,但属性会被拆开成两个运行步骤。构建文件束,转译成目标的输出文件。

var gulp = require('gulp'),
  rollup = require('rollup'),
  rollupTypescript = require('rollup-plugin-typescript')
;

gulp.task('build', function () {
  return rollup.rollup({
    entry: "./src/main.ts",
    plugins: [
      rollupTypescript()
    ],
  })
    .then(function (bundle) {
      bundle.write({
        format: "umd",
        moduleName: "library",
        dest: "./dist/library.js",
        sourceMap: true
      });
    })
});

原文:https://rollupjs.org/#using-rollup-with-gulp