Rollup 是一個 JavaScript 的打包工具,目前我們常使用的 Webpack 也常拿來跟他做比較,基本上兩者皆能達到我們想要的效果,但其各自有較擅長的領域,Webpack 適合應用程式的打包,而 Rollup 則比較適合 library 的打包,另外他使用上也比 Webpack 簡單一些,接著就看一下怎麼使用吧!
首先我們開一個新專案,使用指令建立 package.json
$ npm init -y
然後我們簡單的寫一些東西
// index.js
const myFunction = async () => {
console.log('myFunction')
}
myFunction()
export default myFunction
運行後可以看到結果,如下:
$ node index.js
myFunction
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
const 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.js
import 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
打包後會發現有一些錯誤,這些錯誤會靠著插件來解決,所以我們先看看有哪些常見的插件可以使用
resolve 協助我們從 node_modules
中找到我們安裝的插件
$ npm install @rollup/plugin-node-resolve --save-dev
// rollup.config.js
import { 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
commonjs 將 CommonJS
轉換為 ES6 Module
$ npm install @rollup/plugin-commonjs --save-dev
// rollup.config.js
import 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
json 將 .json
檔案轉換為 ES6 Module
$ npm install @rollup/plugin-json --save-dev
// rollup.config.js
import json from '@rollup/plugin-json'
const config = {
input: 'index.js',
output: {
name: 'bundle',
file: 'dist/bundle.js',
format: 'umd'
},
plugins: [
json()
]
}
export default config
builtins 與 globals 將一些 Node.js
內的全域變數變成 ES6 Module
$ npm install rollup-plugin-node-builtins --save-dev
$ npm install rollup-plugin-node-globals --save-dev
// rollup.config.js
import 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
babel 將 ES6 的語法編譯為瀏覽器看得懂的版本,另外還要下載它的核心
$ npm install @rollup/plugin-babel --save-dev
$ npm install @babel/core --save-dev
// rollup.config.js
import { 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.js
const config = {
presets: [
[
'@babel/preset-env'
]
]
}
export default config
最後在進入點加入 runtime.js
使其正常編譯
// index.js
import 'regenerator-runtime/runtime.js'
terser 用來將程式碼壓縮
$ npm install rollup-plugin-terser --save-dev
// rollup.config.js
import { 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.js
import { 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
// rollup.config.js
import { 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.js
import { 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 阿,搞這一大堆的搞了好幾天,真的很苦啊嗚嗚,希望不要有人再掉進這個大坑
我也是常常想要使用第三方的npm模組,結果總是出一堆問題...
請問是從哪邊找到這些套件對應的使用情況?
rollup-plugin-node-builtins
rollup-plugin-node-globals
還是不知道什麼情況下要加入這些套件
主要原因是 rollup 跳出的 Error log 方向都好歪...
我自己也是不斷的 try and error,google 找答案的時間都比寫 code 時間長了,globals 跟 builtins 主要是用 node 打包時會用到這些東西