介绍
如果需要直接开发项目,webpack 是合适的,它将图片、js、css等视作资源,但本身比较笨重,会稍微增大代码的体积;
如果要开发js库,就可以使用配置简单且轻量的 rollup 了。
特性
-
能够支持模块化开发,使开发者能够使用 ES6 模块的方式编写代码;
-
支持 ES6 模块,能够从库中单独引入需要的函数;
-
拥有 Tree-Shaking 的能力,能够对代码进行静态分析,并剔除未使用到的代码;
import { ajax } from './utils';
-
对比 commonJS:如果使用 commonJS,需要导入整个三方库,然后简单的通过代码压缩工具查找未使用变量,效率没这么高;
const utils = require( './utils' );
-
输入:可以通过使用插件来支持 commonJS 模块;
-
输出:可以将代码编译为 umd/commonJS 格式实现对 Node.js 等环境的支持。
安装
npm install --global rollup
🐢 实际做项目时,也可以进行本地安装。
配置方式-命令行
下面的例子将
main.js
作为应用的入口,将所有的引入都编译到单文件bundle.js
中。
用于浏览器:
# 编译为供 <script> 调用的立即执行函数
rollup main.js --file bundle.js --format iife
用于 Node.js:
# 编译为 CommonJS 模块
rollup main.js --file bundle.js --format cjs
同时用于浏览器和 Node.js:
# 需要为 UMD 格式的包指定一个名称,否则会报错
rollup main.js --file bundle.js --format umd --name "myBundle"
配置方式-配置文件
配置文件是一个导出配置对象的ES模块,通常位于项目根目录,并命名为 rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
}
};
使用 .cjs
的拓展名,配置文件可以使用 commonJS
模块,就能支持 require
和 module.exports
语法;
构建不同的输出
- 根据不同的入口构建不同的 bundle,可配置为对象数组;
- 为相同的入口构建多个 bundle,可以将输出项写成数组。
export default [{
input: 'main-a.js',
output: {
file: 'dist/bundle-a.js',
format: 'cjs'
}
}, {
input: 'main-b.js',
output: [
{
file: 'dist/bundle-b1.js',
format: 'cjs'
},
{
file: 'dist/bundle-b2.js',
format: 'es'
}
]
}];
异步构建
Rollup 可以处理结果为对象/数组形式的 promise。
例子一
import fetch from 'node-fetch';
export default fetch('/some-remote-service-or-file-which-returns-actual-config');
例子二
export default Promise.all([
fetch('get-config-1'),
fetch('get-config-2')
])
自定义文件路径
在命令行加上 --config
或者 -c
的选项,就可以使用指定的配置文件。
rollup --config rollup.config.dev.js
忽略文件名,会按照特定顺序加载配置文件
rollup.config.mjs -> rollup.config.cjs -> rollup.config.js
rollup --config
使用插件
使用插件能够拓展 Rollup 本身的行为,如使用 NPM 安装导入模块,使用 Babel 编译代码,运行 JSON 文件。
示例一
使 Rollup 支持从 JSON 文件中导入数据。
安装
npm install --save-dev @rollup/plugin-json
使用
src/main.js
import { version } from '../package.json';
export default function () {
console.log('version ' + version);
}
配置
rollup.config.js
import json from '@rollup/plugin-json';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [ json() ]
};
🐢 不使用这个插件,也能从 JSON 文件中导入数据,参考官方示例。
示例二
对输出的代码进行压缩,来生成压缩后的 bundles。
npm install --save-dev rollup-plugin-terser
配置
rollup.config.js
import {terser} from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs',
plugins: [terser()]
},
};
🌟 注意插件的使用时机,压缩适合在 Rollup 分析代码后使用,故配置在 output.plugins
中。
集成三方工具
使用npm包
在代码中使用任意包
npm install the-answer
src/main.js
import answer from 'the-answer';
export default function () {
console.log('the answer is ' + answer);
}
支持 Rollup 找到外部模块
npm install --save-dev @rollup/plugin-node-resolve
rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [ resolve() ]
};
🐙 如果没有使用插件 @rollup/plugin-node-resolve
,那么输出的 bundle.js
将不会注入使用到的包,并在控制台提示:
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
处理commonJS
使用插件 @rollup/plugin-commonjs 能够支持依赖中的 commonJS
,注意应该在其他插件前调用。
前置依赖
如果构建一个具有前置依赖的库(类似 React / Loadsh),按照下面的方式设置,rollup 将会打包所有的引入项:
import _ from 'lodash';
- 可以通过
external
指定外部引入,它们不会被打包到 bundle 当中去; - 构建的包如果是提供给浏览器使用,指定
external
会导致依赖找不到。
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [resolve({
// 将自定义选项传递给解析插件,【推测为外部引入的查找路径】
customResolveOptions: {
moduleDirectory: 'node_modules'
}
})],
// 指出哪些模块需要被视为外部引入
external: ['lodash']
};
Babel
能够使 rollup 支持最新的 JavaScript 特性。
安装插件并配置
npm i -D @rollup/plugin-babel @rollup/plugin-node-resolve
npm i -D @babel/core @babel/preset-env
rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [
resolve(),
babel({ babelHelpers: 'bundled' })
]
};
配置 babel
src/.babelrc.json
{
"presets": [
["@babel/env", {"modules": false}]
]
}
👻 设置 modules: false
来避免 babel 将模块转化为 commonJS;
🐢 babel 将在正在编译的文件的当期目录中查找 .babelrc
,如果不存在,就顺着目录往上找。
添加es6语法以方便测试
src/main.js
import answer from 'the-answer';
export default () => {
console.log(`the answer is ${answer}`);
}
Gulp
Gulp 可以理解 Rollup 返回的 Promise。
const gulp = require('gulp');
const rollup = require('rollup');
const rollupTypescript = require('@rollup/plugin-typescript');
gulp.task('build', async function () {
const bundle = await rollup.rollup({
input: './src/main.ts',
plugins: [
rollupTypescript()
]
});
await bundle.write({
file: './dist/library.js',
format: 'umd',
name: 'library',
sourcemap: true
});
});
🐳 这里使用了 Rollup 的 JavaScript API,在内存中构建包,然后输出到硬盘中。
示例一
rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import pkg from './package.json';
export default [
// 对浏览器友好的umd构建
{
input: 'src/main.js',
output: {
name: 'howLongUntilLunch',
file: pkg.browser, // 输出文件名
format: 'umd'
},
plugins: [
resolve(), // 支持 Rollup 找到外部模块
commonjs() // 支持依赖中的 commonJS
]
},
// commonJS(用于Node)
// ES module(用于bundlers)
{
input: 'src/main.js',
// 指出模块为外部引入,将不会被打包到 bundle 中
external: ['ms'],
output: [
{ file: pkg.main, format: 'cjs' },
{ file: pkg.module, format: 'es' }
]
}
];
🐳 示例项目安装了外部依赖 ms
,并引入到 src/main.js
文件中。
package.json
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w"
}
-c 指定配置文件,默认是 rollup.config.js;
-w 监听,在输入(包括依赖)改变时重新构建(bundle)。
示例二
rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
// 通过命令行的(-w/-watch)判断是否生产环境
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
file: 'public/bundle.js',
format: 'iife', // 供 <script> 调用的立即执行函数
sourcemap: true // 生成sourcemap,使错误和日志能够指向原模块
},
plugins: [
resolve(),
commonjs(),
production && terser() // 生产环境时,压缩
]
};
🐳 示例项目安装了外部依赖 date-fns/format
,并作为 src/main.js
的深层依赖。
package.json
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w",
"dev": "npm-run-all --parallel start watch", // 并行执行
"start": "serve public"
}
生成bundle规律总结
- 编写源码(作为配置入口)使用 es 语法,编写配置使用 commonJs 语法,可以生成 bundle
使用 es 的语法编写源码和配置文件
编译方式 | 导入语法 | 导出语法 |
---|---|---|
cjs | 无,内容被注入 | commonJS |
es | 无,内容被注入 | es |
使用 commonJS 的语法编写源码和配置文件
编译方式 | 导入语法 | 导出语法 |
---|---|---|
cjs | commonJS | commonJS |
es | commonJS | commonJS |
使用 commonJS 的语法编写源码和配置文件 + @rollup/plugin-commonjs 处理
编译方式 | 导入语法 | 导出语法 |
---|---|---|
cjs | 无,内容被注入 | commonJS |
es | 无,内容被注入 | es |
附录
类型 | 说明 |
---|---|
文档 | 命令行标志 |
文档 | 配置选项 |
文档 | 插件列表 |
文档 | 插件开发 |
未总结特性 | JavaScript API、代码分割 |
参考资料:
补充的话
如果这篇笔记能够帮助到你,请帮忙在 github 上点亮 star
,这对我非常重要,感谢!