Rollup的基本使用
rollup.js
是一個模塊打包工具,可以使項目從一個入口文件開始,將所有使用到的模塊文件都打包到一個最終的發布文件中,Rollup
極其適合構建一個工具庫,Vue.js
源碼就是通過Rollup
打包構建的。
描述
rollup
對代碼模塊使用新的標准化格式,這些標准都包含在JavaScript
的ES6
版本中,而不是以前的特殊解決方案,如CommonJS
和AMD
等,也就是說rollup
使用ES6
的模塊標准,這意味着我們可以直接使用import
和export
而不需要引入babel
,當然,在現在的項目中,babel
可以說是必用的工具,此外rollup
實現了另一個重要特性叫做tree-shaking
,這個特性可以幫助你將無用代碼,即沒有使用到的代碼自動去掉,這個特性是基於ES6
模塊的靜態分析的,也就是說,只有export
而沒有import
的變量是不會被打包到最終代碼中的。
示例
我的一個小油猴插件就是通過rollup
打包的,GreasyFork
地址為https://greasyfork.org/zh-CN/scripts/405130
,全部源碼地址為https://github.com/WindrunnerMax/TKScript
,使用npm run build
即可打包構建,package.json
文件與rollup.config.js
文件配置如下。
{
"name": "TKScript",
"version": "1.0.0",
"description": "Tampermonkey",
"scripts": {
"build": "rollup -c"
},
"author": "Czy",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"install": "^0.13.0",
"npm": "^6.14.5",
"rollup": "^2.18.2",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-postcss": "^3.1.2",
"rollup-plugin-uglify": "^6.0.4",
"rollup-plugin-userscript-metablock": "^0.2.5"
}
}
import postcss from "rollup-plugin-postcss";
import babel from "rollup-plugin-babel";
// import { uglify } from "rollup-plugin-uglify";
import metablock from "rollup-plugin-userscript-metablock";
const config = {
postcss: {
minimize: true,
extensions: [".css"],
},
babel: {
exclude: ["node_modules/**"],
presets: [
[
"@babel/env", {
modules: false,
targets: "last 2 versions, ie >= 10"
}
]
]
},
}
export default [{
input: "./src/copy/src/index.js",
output: {
file: "./dist/copy.js",
format: "iife",
name: "copyModule"
},
plugins: [
postcss(config.postcss),
babel(config.babel),
// uglify(),
metablock({
file: "./src/copy/meta.json"
})
]
},{
input: "./src/site-director/src/index.js",
output: {
file: "./dist/site-director.js",
format: "iife",
name: "linkModule"
},
plugins: [
postcss(config.postcss),
babel(config.babel),
// uglify(),
metablock({
file: "./src/site-director/meta.json"
})
]
}];
使用方法
安裝
- 全局安裝:
npm install rollup -g
。 - 項目安裝:
npm install rollup --save-dev
、yarn add rollup -D
。
命令行工具
-i, --input <filename>
: 要打包的文件(必須)。-o, --file <output>
: 輸出的文件(如果沒有這個參數,則直接輸出到控制台)。-f, --format <format>
: 輸出的文件類型。amd
: 異步模塊定義,用於像RequestJS
這樣的模塊加載器。cjs
:CommonJS,
適用於Node
或Browserify/webpack
。es
: 將軟件包保存為ES
模塊文件。iife
: 一個自動執行的功能,適合作為script
標簽這樣的,只能在瀏覽器中運行。umd
: 通用模塊定義,以amd
、cjs
和iife
為一體。system
:SystemJS
加載器格式。
-e, --external <ids>
: 將模塊ID
的逗號分隔列表排除。-g, --globals <pairs>
: 以moduleID:Global
鍵值對的形式,用逗號分隔開任何定義在這里模塊ID
定義添加到外部依賴。-n, --name <name>
: 生成UMD
模塊的名字。-m, --sourcemap
: 生成sourcemap
。--amd.id
:AMD
模塊的ID
,默認是個匿名函數。--amd.define
: 使用Function
來代替define
。--no-strict
: 在生成的包中省略use strict;
。--no-conflict
: 對於UMD
模塊來說,給全局變量生成一個無沖突的方法。--intro
: 在打包好的文件的塊的內部(wrapper
內部)的最頂部插入一段內容。--outro
: 在打包好的文件的塊的內部(wrapper
內部)的最底部插入一段內容。--banner
: 在打包好的文件的塊的外部(wrapper
外部)的最頂部插入一段內容。--footer
: 在打包好的文件的塊的外部(wrapper
外部)的最底部插入一段內容。--interop
: 包含公共的模塊(這個選項是默認添加的)。-w, --watch
: 監聽源文件是否有改動,如果有改動,重新打包。--silent
: 不要將警告打印到控制台。-h, --help
: 輸出幫助信息。-v, --version
輸出版本信息。
配置文件
// rollup.config.js
export default {
// 核心選項
input, // 必須
external,
plugins,
// 額外選項
onwarn,
// danger zone
acorn,
context,
moduleContext,
legacy
output: { // 必須 (如果要輸出多個,可以是一個數組)
// 核心選項
file, // 必須
format, // 必須
name,
globals,
// 額外選項
paths,
banner,
footer,
intro,
outro,
sourcemap,
sourcemapFile,
interop,
// 高危選項
exports,
amd,
indent
strict
},
};
input
input
、rollup -i,--input
,打包入口文件路徑,參數類型為String | String [] | { [entryName: string]: string }
。
使用數組或者字符串作為選項值的時候的時候,默認使用的是文件的原始名稱,作為文件的basename
,可以在output:entryFileNames = entry-[name].js
配置選項作為[name]
動態參數傳遞進去。
input: "./src/index.js";
input: ["./src/index.js", "./other/index.js"];
用鍵值對{key: value}
的選項值作為參數,使用的對象的鍵作為文件的basename
,用來在output:entryFileNames
配置選項作為[name]
動態參數傳遞進去。
input: { main: "./src/index.js", vendor: "./other/index.js" }
external
external
、rollup -e,--external
, 維持包文件指定id
文件維持外鏈,不參與打包構建 參數類型為String[] | (id: string, parentId: string, isResolved: boolean) => boolean
。
- 當
format
類型為iife
或者umd
格式的時候需要配置output.globals
選項參數以提供全局變量名來替換外部導入。 - 當
external
是一個函數的時候,各個參數代表的含義分別是:id
,所有導入的文件id
,即import
訪問的路徑;parent
,import
所在的文件絕對路徑;isResolved
,表示文件id
是否已通過插件處理過。
{
// ...,
external: [
'some-externally-required-library',
'another-externally-required-library'
]
}
// or
{
// ...,
external: (id, parent, isResolved) => {
return true;
}
}
plugins
可以提供rollup
很多插件選項,參數類型為Plugin | (Plugin | void)[]
。
{
// ...,
plugins: [
resolve(),
commonjs(),
isProduction && (await import("rollup-plugin-terser")).terser()
]
}
onwarn
攔截警告信息,如果沒有提供,警告將被復制並打印到控制台,警告是至少有一個code
和message
屬性的對象,我們可以控制如何處理不同類型的警告。
onwarn (warning) {
// 跳過某些警告
if (warning.code === 'UNUSED_EXTERNAL_IMPORT') return;
// 拋出異常
if (warning.code === 'NON_EXISTENT_EXPORT') throw new Error(warning.message);
// 控制台打印一切警告
console.warn(warning.message);
}
許多警告也有一個loc
屬性和一個frame
,可以定位到警告的來源。
onwarn ({ loc, frame, message }) {
// 打印位置(如果適用)
if (loc) {
console.warn(`${loc.file} (${loc.line}:${loc.column}) ${message}`);
if (frame) console.warn(frame);
} else {
console.warn(message);
}
}
acorn
這是danger zone
,修改rollup
解析js
配置,rollup
內部使用的acorn
庫解析js, acorn
庫提供了解析js
的相關配置api
,一般很少需要修改。在下面這個例子中,這個acorn-jsx
插件和使用babel
並不是同一個意思,這個插件的左右是讓acornjs
解析器能認識jsx
語法,經過rollup
打包后展示的還是jsx
語法,而babel
會直接修改jsx
結構成為普通js
語法。
import jsx from "acorn-jsx";
export default {
// ...
acornInjectPlugins: [
jsx()
]
};
context
默認情況下,模塊的上下文,即頂級的this
的值為undefined
,在極少數情況下,可能需要將其更改為其他內容,例如window
。
moduleContext
和context
一樣,但是每個模塊可以是id:context
對的對象,也可以是id=>context
函數。
legacy
為了增加對諸如IE8
之類的舊版環境的支持,通過剝離更多可能無法正常工作的現代化的代碼,其代價是偏離ES6
模塊環境所需的精確規范。
output
output
是輸出文件的統一配置入口, 包含很多可配置選項 參數類型為Object | Array
,單個輸出為一個對象,要輸出多個,可以是一個數組。
output.file
output.file
、rollup -o,--file
,必填,對於單個文件打包可以使用該選項指定打包內容寫入帶路徑的文件,參數類型為String
。
output: {
file: "./dist/index.js"
}
output.format
output.format
、rollup -f,--format
,必填,打包格式類型 ,配置可選項有amd
、cjs
、es
、iife
、umd
、system
,選項說明同命令行配置選項,參數類型為String
。
output: {
format: "iife"
}
output.name
output.format
,rollup -f,--format
生成包名稱,參數類型為String
。
export default {
// ...,
output: {
name: "bundle"
}
};
output.globals
output.globals
,rollup -g,--globals
,配合配置external
選項指定的外鏈在umd
和iife
文件類型下提供的全局訪問變量名參數類型,參數類型為{ [id: String]: String } | ((id: String) => String)
。
export default {
// ...,
globals: {
jquery: "$"
}
};
output.paths
它獲取一個ID
並返回一個路徑,或者id: path
對的Object
,在提供的位置,這些路徑將被用於生成的包而不是模塊ID
,從而允許從CDN
加載依賴關系。
// app.js
import { selectAll } from 'd3';
selectAll('p').style('color', 'purple');
// ...
// rollup.config.js
export default {
input: 'app.js',
external: ['d3'],
output: {
file: 'bundle.js',
format: 'amd',
paths: {
d3: 'https://d3js.org/d3.v4.min'
}
}
};
// bundle.js
define(['https://d3js.org/d3.v4.min'], function (d3) {
d3.selectAll('p').style('color', 'purple');
// ...
});
output.banner
字符串前置到文件束bundle
,banner
選項不會破壞sourcemaps
,參數類型為String
。
export default {
// ...,
output: {
banner: "/* library version " + version + " */",
}
};
output.footer
字符串前置到文件束bundle
,footer
選項不會破壞sourcemaps
,參數類型為String
。
export default {
// ...,
output: {
footer: "/* follow me on Github! */",
}
};
output.intro
類似於output.banner
,如果說banner
和footer
是在文件開始和結尾添加字符串,那么intro
和outro
就是在被打包的代碼開頭和結尾添加字符串了。
export default {
// ...,
output: {
intro: "/* library version " + version + " */",
}
};
output.outro
類似於output.footer
,如果說banner
和footer
是在文件開始和結尾添加字符串,那么intro
和outro
就是在被打包的代碼開頭和結尾添加字符串了。
export default {
// ...,
outro: {
footer: "/* follow me on Github! */",
}
};
output.sourcemap
sourcemap
、rollup -m,--sourcemap, --no-sourcemap
,如果true
,將創建一個單獨的sourcemap
文件,如果inline, sourcemap
將作為數據URI
附加到生成的output
文件中。
output.sourcemapFile
生成的包的位置,如果這是一個絕對路徑,sourcemap
中的所有源代碼路徑都將相對於它,map.file
屬性是sourcemapFile
的基本名稱basename
,因為sourcemap
的位置被假定為與bundle
相鄰,如果指定output
,sourcemapFile
不是必需的,在這種情況下,將通過給bundle
輸出文件添加.map
后綴來推斷輸出文件名,一般應用場景很少,在特殊場景需要改變sourcemap
的指向文件地址時才會用到。
output.interop
是否添加interop
塊,默認情況下interop: true
,為了安全起見,如果需要區分默認和命名導出,則rollup
會將任何外部依賴項default
導出到一個單獨的變量,這通常只適用於您的外部依賴關系,例如與Babel
,如果確定不需要它,則可以使用interop: false
來節省幾個字節。
output.exports
使用什么導出模式,默認為auto
,它根據entry
模塊導出的內容猜測你的意圖。
default
: 如果使用export default...
僅僅導出一個文件,那適合用這個。named
: 如果導出多個文件,適合用這個。none
: 如果不導出任何內容,例如正在構建應用程序,而不是庫,則適合用這個。
output.amd
打包amd
模塊相關定義。
amd.id
: 用於AMD/UMD
軟件包的ID
。amd.define
: 要使用的函數名稱,而不是define
。
output.indent
是要使用的縮進字符串,對於需要縮進代碼的格式amd
、iife
、umd
,也可以是false
無縮進或true
默認自動縮進。
output.strict
true
或false
,默認為true
,是否在生成的非ES6
軟件包的頂部包含usestrict pragma
,嚴格來說ES6
模塊始終都是嚴格模式,所以應該沒有很好的理由來禁用它。
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://www.rollupjs.com/
https://segmentfault.com/a/1190000010628352
https://github.com/JohnApache/rollup-usage-doc