Skip to main content

[note] rollup-js 筆記

keywords: 打包, bundle#

rollup.js @ official website

Quick Start#

可以參考 Rollup 的這兩個啟動專案:

假設應用程式的進入點(entry point)是 main.js,打包後的檔案稱作 bundle.js,則

給瀏覽器(iife):

# compile to a <script> containing a self-executing function ('iife')
rollup main.js --file bundle.js --format iife

給 Node.js(cjs):

# compile to a CommonJS module ('cjs')
rollup main.js --file bundle.js --format cjs

同時給瀏覽器和 Node.js(umd):

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

發佈 ES Modules#

為了確保你的 ES Modules 可以立即 Node.js 或 Webpack 這類 CommonJS 的工具所使用,你可以使用 Rollup 來編譯成 UMD 或 CommonJS 的格式,接著在 package.json 中的 main 屬性指定該打包好的檔案,如果你的 package.json 中也有 module 這個屬性,則 ESM-aware 的工具(例如,Rollup 和 web pack 2+)將會直接載入 ES Module 的版本

Plugins#

  • @rollup/plugin-commonjs:可以將以 CommonJS 寫的模組轉換成 ES6,如此就可以在 Rollup 中匯入 CommonJS 的模組。
  • @rollup/plugin-node-resolve:rollup 才會解析 node_modules 裡面的第三方套件,如果自己的套件中有用到其他第三方的套件時需安裝。
  • rollup-plugin-terser:可以用來壓縮打包後的檔案

Command Line Interface (CLI)#

Command Line 可用參數#

Command line flags @ rollup.js > CLI

# 直接透過 CLI 打包
# -f 是 --format <format>, -o 是 --file <output>
$ rollup index.js -f cjs -o bundle.js
# 根據 rollup.config.js 打包
# -c 是 --config <filename>,沒填 filename 預設會直接吃 rollup.config.js
$ rollup -c

設定檔(Configuration Files)#

configuration files @ rollup.js > CLI

若下面情況一定要使用 Rollup 設定檔:

  1. 一個專案打包成多支 output 檔案
  2. 使用 Rollup 的外掛(plugin),像是 @rollup/plugin-node-resolve@rollup/plugin-commonjs

透過 rollup CLI 的 --config-c 可以執行設定檔 :

# Rollup 會讀取 rollup.config.js
rollup --config
# Rollup 會讀取自定義檔名的設定檔
rollup --config my.config.js
# .js and .mjs are supported
rollup --config my.config.mjs

Rollup 的設定檔名稱為 rollup.config.js,它用 ES Module 或 CommonJS 來寫都可以:

// rollup.config.js
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import resolve from 'rollup-plugin-node-resolve';
import url from 'rollup-plugin-url';
import pkg from './package.json';
export default {
input: 'src/index.js',
output: [
{
file: pkg.main, // 會去讀取 package.json 的 main 欄位
format: 'cjs', // Common JS
sourcemap: true,
},
{
file: pkg.module, // 會去讀取 package.json 的 module 欄位
format: 'es', // ES Module
sourcemap: true,
},
{
name: 'myBundle',
file: 'dist/bundle.umd.js',
format: 'umd', // 給瀏覽器和 Node.js
sourcemap: true,
},
{
file: 'dist/bundle.js',
format: 'iife', // 給瀏覽器
sourcemap: true,
},
],
plugins: [
external(),
url({ exclude: ['**/*.svg'] }),
babel({
exclude: 'node_modules/**',
}),
resolve(),
commonjs(),
],
};

其他#

With NPM Packages#

keywords: @rollup/plugin-node-resolve, @rollup/plugin-commonjs#

With NPM Packages @ GitHub

+ import resolve from '@rollup/plugin-node-resolve';
+ import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/index.js',
output: [
{
file: 'dist/index.cjs.js',
format: 'cjs',
},
{
file: 'dist/index.esm.js',
format: 'esm',
},
],
+ plugins: [resolve(), commonjs()]
};

(!) Unresolved dependencies: @rollup/plugin-node-resolve#

需要安裝 @rollup/plugin-node-resolve,它會讓 rollup 知道如何找到外部的模組,並把它放入打包好的檔案中。

如果沒有使用此 plugin 的話,安裝的套件不會一起被打包,使用者需要自行安裝:

import answer from 'the-answer';
function index() {
console.log('answer ' + answer);
}
export default index;

若有使用此 plugin,則會一併把該套件或套件執行後的結果打包進去:

var index$1 = 42; // 打包後的結果
function index() {
console.log('answer ' + index$1);
}
export default index;

@rollup/plugin-commonjs#

@rollup/plugin-commonjs @ guide > with npm packages

由於打包過的檔案不一定支援 ESM 的使用,透過 @rollup/plugin-commonjs 可以把 CommoJS modules 轉成 ES6 後,放到 Rullup 打包好的檔案內。

note

官方建議 commonjs 先執行後再執行 babel;resovle 先執行後再執行 commonjs(參考 #1148),但搭配 React 時,可能會需要先 babel 再 commonjs (參考 #2518#247' 和 #295)。

Peer Dependencies:告訴 rollup 哪些 module 不需要被打包#

透過 external 可以告訴 rollup 哪些檔案不需要一起被打包,這些檔案通常是 peerDependencies,像是 lodash 或 React,是需要使用此套件的人自己安裝的。

// rollup.config.js
export default {
// 可以用陣列的方式來定義
external: ['lodash', 'styled-components', '/@babel/runtime/'], // 陣列不接受 wildcard 的用法
// 可以用 function 的方式,回傳 true 表示它是 external
external: (id) => /lodash/.test(id),
};

Babel#

用途#

使用 Babel 的話可以把專案程式碼打包成支援更舊版本語法。

--- a/dist/index.esm.js
+++ b/dist/index.esm.js
@@ -2,15 +2,14 @@ var version = "1.0.0";
var index$1 = 42;
-// 沒使用 babel
-var getAnswer = () => {
- console.log(`the answer is ${index$1}`);
-};
+// 有使用 babel
+var getAnswer = (function () {
+ console.log("the answer is ".concat(index$1));
+});
function index () {
console.log('version ' + version);
getAnswer();
}
-
console.log('version ' + version);
getAnswer();

babelHelpers: runtime#

設定 rollup.config.js,並套用 babelHelpers: 'runtime'

// rollup.config.js
import { babel } from '@rollup/plugin-babel';
export default {
plugins: [
babel({
+ babelHelpers: 'runtime',
}),
],
+ external: [/@babel\/runtime/],
};

使用 babelHelpers: 'runtime' 時,需要搭配 @babel/plugin-transform-runtime

// babel.config.json
{
"name": "mono-components-sandbox",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
+ "@babel/plugin-transform-runtime": "^7.14.3",
"@babel/preset-env": "^7.14.4",
"@babel/preset-react": "^7.13.13",
}
}

並且將該 plugin 設定到 babel.config.js 中:

// babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
[
'@babel/preset-react',
{
runtime: 'automatic',
},
]
],
+ plugins: ['@babel/plugin-transform-runtime'],
};

TypeScript#

搭配 @babel/preset-react 來編譯 TS#

要使用 Babel 來編譯 TypeScript 檔案,需要先讓 rollup 認得 TS 的檔案,所以會需要先安裝 @rollup/plugin-node-resolve,並且修改 rollup.config.js

// rollup.config.js
import { babel } from '@rollup/plugin-babel';
+ import resolve from '@rollup/plugin-node-resolve';
+ const extensions = ['.js', '.jsx', '.ts', '.tsx'];
export default {
- input: 'lib/index.js'
+ input: 'lib/index', // js | ts
// ...
plugins: [
+ resolve({
+ extensions,
+ }),
babel({
rootMode: 'upward',
babelHelpers: 'runtime',
+ extensions,
}),
],
external: [/@babel\/runtime/],
};

如果是搭配 @babel/preset-react 而不是使用 @rollup/plugin-typescript 的話,需要額外透過 tsc 來產生 type definition。

透過 tsc 產生 type definition#

  • scripts 中新增一個 build:ts 的指令來透過 tsc 產生 type definition 檔案
  • 建立 types 欄位,這個欄位很重要,目的是要讓載入這個 component 的使用者知道從哪裡去找到 Type Definition Files(參考:Including declarations in your npm package @ TypeScript)
// /packages/a/package.json
{
"name": "@mono-sandbox/a",
"version": "0.0.4",
"module": "dist/index.esm.js",
+ "types": "dist/lib/index.d.ts",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"scripts": {
"build": "rollup -c ../../rollup.config.js",
+ "build:ts": "tsc --emitDeclarationOnly --project tsconfig.json",
"clean": "rimraf dist *.tsbuildinfo",
"test": "echo \"Error: run tests from root\" && exit 1"
}
}

這時候執行 npm run build:ts 並不會正常執行,而是會出現下一段落的錯誤訊息:

安裝 @types/react#

如果沒有安裝 @types/react 的話,會出現以下錯誤訊息:

Cannot find module 'react/jsx-runtime' or its corresponding type declarations.

Cannot find module react/jsx-runtime

只需要安裝 @types/react 即可:

// package.json
{
"name": "mono-components-sandbox",
"devDependencies": {
"@rollup/plugin-node-resolve": "^13.0.0",
+ "@types/react": "^17.0.8",
"lerna": "^4.0.0",
"rimraf": "^3.0.2",
},
"workspaces": [
"packages/*"
]
}
Last updated on