Rollup 是一个 JavaScript 的打包工具,目前我们常使用的 Webpack 也常拿来跟他做比较,基本上两者皆能达到我们想要的效果,但其各自有较擅长的领域,Webpack 适合应用程式的打包,而 Rollup 则比较适合 library 的打包,另外他使用上也比 Webpack 简单一些,接着就看一下怎么使用吧!
建立专案
首先我们开一个新专案,使用指令建立 package.json
$ npm init -y
然后我们简单的写一些东西
// index.jsconst myFunction = async () => { console.log('myFunction')}myFunction()export default myFunction
运行后可以看到结果,如下:
$ node index.jsmyFunction
ES6 Module
Rollup 是一个针对 ES6 Module
所设计的打包工具,所以我们必须使用 ES6 Module
来做撰写,而使用方法有以下两种,选一种即可开始使用啰
ES Module
档案的副档名改为 .mjs
在 package.json
内加入 { "type": "module" }
开始打包
首先安装今天的主角 Rollup
$ npm install --global rollup
接着可以执行指令进行打包
$ rollup index.js --file dist/bundle.js --format umd --name "myBundle"
-f, --format
:档案输出格式(amd, cjs, es, iife, umd, system)-n, --name
:档案全域名称-m, --sourcemap
:产生 sourcemap
-w, --watch
:监听档案变化即时编译-c, --config
:使用 rollup.config.js
的设定rollup.config.js
当需要的设定变多之后,我们可以创建 rollup.config.js
来详细写入相关的设定,以下有几个常用设定,详细的可以看官方文件
// rollup.config.jsconst config = { input: 'index.js', // 进入点 plugins: [], // 插件 external: [], // 外部插件 onwarn(warning, warn) { // 自定义警告 // do something... }, treeshake: true, // 删除没用到的程式码 output: { // 输出档案 name: 'bundle', // 全域名称 file: 'dist/bundle.js', // 输出档案 format: umd, // 输出格式 sourcemap: true // 是否产生 sourcemap }}export default config
最后我们可以在 package.json
加入指令,方便之后编译
// package.json{ "scripts": { "build": "rollup -c" }}
打包成果如下:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bundle = factory());}(this, (function () { 'use strict'; const myFunction = async () => { console.log('myFunction'); }; myFunction(); return myFunction;})));
安装插件
通常打包时我们通常还会用到许多其他的功能,而插件就是来补齐这些功能,首先我们先修改一下程式码,安装一个 Demo 用的插件,并小小修改一下程式码
$ npm install the-answer
接着程式码如下:
// index.jsimport answer from 'the-answer'const action = () => { return new Promise((res, rej) => { setTimeout(() => { res(answer) }, 3000) })}const myFunction = async () => { const answer = await action() console.log(answer)}myFunction()export default myFunction
打包后会发现有一些错误,这些错误会靠着插件来解决,所以我们先看看有哪些常见的插件可以使用
@rollup/plugin-node-resolve
resolve 协助我们从 node_modules
中找到我们安装的插件
$ npm install @rollup/plugin-node-resolve --save-dev
// rollup.config.jsimport { nodeResolve } from '@rollup/plugin-node-resolve'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ nodeResolve() // 如果要在浏览器使用需要加入设定如下 // nodeResolve({ browser: true, preferBuiltins: true }) ]}export default config
@rollup/plugin-commonjs
commonjs 将 CommonJS
转换为 ES6 Module
$ npm install @rollup/plugin-commonjs --save-dev
// rollup.config.jsimport commonjs from '@rollup/plugin-commonjs'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ commonjs() // Node.js 有些套件需要加入以下设定才会正常 // commonjs({ include: ['node_modules/**'] }) ]}export default config
@rollup/plugin-json
json 将 .json
档案转换为 ES6 Module
$ npm install @rollup/plugin-json --save-dev
// rollup.config.jsimport json from '@rollup/plugin-json'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ json() ]}export default config
rollup-plugin-node-builtins & rollup-plugin-node-globals
builtins 与 globals 将一些 Node.js
内的全域变数变成 ES6 Module
$ npm install rollup-plugin-node-builtins --save-dev$ npm install rollup-plugin-node-globals --save-dev
// rollup.config.jsimport builtins from 'rollup-plugin-node-builtins'import globals from 'rollup-plugin-node-globals'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ globals(), builtins() ]}export default config
@rollup/plugin-babel
babel 将 ES6 的语法编译为浏览器看得懂的版本,另外还要下载它的核心
$ npm install @rollup/plugin-babel --save-dev$ npm install @babel/core --save-dev
// rollup.config.jsimport { babel } from '@rollup/plugin-babel'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ babel({ babelHelpers: 'bundled' }) ]}export default config
接着要编写 babel 的设定档,我们在根目录建立一个 babel.config.js
,并安装 babel 的预设设定
$ npm install @babel/preset-env --save-dev
// babel.config.jsconst config = { presets: [ [ '@babel/preset-env' ] ]}export default config
最后在进入点加入 runtime.js
使其正常编译
// index.jsimport 'regenerator-runtime/runtime.js'
rollup-plugin-terser
terser 用来将程式码压缩
$ npm install rollup-plugin-terser --save-dev
// rollup.config.jsimport { terser } from 'rollup-plugin-terser'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ terser() ]}export default config
以上差不多就是常用的插件,那么我们来把刚刚编译的问题解决吧!
浏览器版本设定
// rollup.config.jsimport { nodeResolve } from '@rollup/plugin-node-resolve'import commonjs from '@rollup/plugin-commonjs'import { babel } from '@rollup/plugin-babel'import { terser } from 'rollup-plugin-terser'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ nodeResolve({ browser: true, preferBuiltins: true }), commonjs(), babel({ babelHelpers: 'bundled' }), terser() ]}export default config
Node.js 版本设定
// rollup.config.jsimport { nodeResolve } from '@rollup/plugin-node-resolve'import builtins from 'rollup-plugin-node-builtins'import globals from 'rollup-plugin-node-globals'import commonjs from '@rollup/plugin-commonjs'import json from '@rollup/plugin-json'import { babel } from '@rollup/plugin-babel'import { terser } from 'rollup-plugin-terser'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd' }, plugins: [ nodeResolve(), globals(), builtins(), commonjs({ include: ['node_modules/**'] }), json(), babel({ babelHelpers: 'bundled' }), terser() ]}export default config
到这边就可以正常打包啰!
外部插件
顺便补充一下,如果想要把插件当成外部插件引用可以照以下设定,以浏览器举例
// rollup.config.jsimport { nodeResolve } from '@rollup/plugin-node-resolve'import commonjs from '@rollup/plugin-commonjs'import { babel } from '@rollup/plugin-babel'const config = { input: 'index.js', output: { name: 'bundle', file: 'dist/bundle.js', format: 'umd', globals: { 'the-answer': 'the-answer' // 全域变数 } }, plugins: [ nodeResolve({ browser: true, preferBuiltins: true }), commonjs(), babel({ babelHelpers: 'bundled' }) ], external: ['the-answer'] // 告知为外部插件}export default config
最后另外提醒一下以下几点
Node.js
与浏览器环境有差异,要分开调整插件的载入顺序会有差异,要特别注意不使用 ES6 Module
撰写的话打包路径有可能会出现错误结语
我只是想打包个 JavaScript 阿,搞这一大堆的搞了好几天,真的很苦啊呜呜,希望不要有人再掉进这个大坑