rollup.js是Javascript的ES模塊打包器,咱們熟知的Vue、React等諸多知名框架或類庫都經過rollup.js進行打包。與Webpack偏向於應用打包的定位不一樣,rollup.js更專一於Javascript類庫打包(雖然rollup.js也能夠提供資源打包,但顯然這不是它的強項)。在咱們學習Vue和React等框架源碼或者本身編寫Javascript類庫時,rollup.js是一條必經之路。javascript
rollup.js能夠將咱們本身編寫的Javascript代碼(經過插件能夠支持更多語言,如Tyepscript)與第三方模塊打包在一塊兒,造成一個文件,該文件能夠是一個庫(Library)或者一個應用(App),在打包過程當中能夠應用各種插件實現特定功能。下圖揭示了rollup.js的運行機制: java
rollup.js的安裝依賴於nodejs,以前的手記中我曾詳細介紹如何經過nvm管理nodejs版本,須要瞭解的小夥伴能夠點擊這裏node
首先全局安裝rollup:npm
npm i rollup -g
複製代碼
安裝成功後,咱們嘗試使用rollup作一個簡單的案例,建立src目錄:vim
mkdir src
複製代碼
在src目錄下建立a.js:api
vim src/a.js
複製代碼
寫入以下代碼,這個模塊很是簡單,僅僅對外暴露一個變量a:數組
const a = 1 export default a 複製代碼
在src目錄下再建立main.js:bash
vim src/main.js
複製代碼
寫入以下代碼,這個模塊會引入模塊a,並對外暴露一個function:babel
import a from './a.js' export default function() { console.log(a) } 複製代碼
經過rollup指令,咱們能夠快速地預覽打包後的源碼,這點和babel很是相似:markdown
$ rollup src/main.js -f es src/main.js stdout... const a = 1; function main() { console.log(a); } export default main; created stdout in 26ms 複製代碼
須要注意的是rollup必須帶有-f
參數,不然會報錯:
$ rollup src/main.js src/main.js stdout... [!] Error: You must specify output.format, which can be one of 'amd', 'cjs', 'system', 'esm', 'iife' or 'umd' https://rollupjs.org/guide/en#output-format-f-format 複製代碼
rollup的報錯提示很是棒,很是有利於咱們定位錯誤和修復問題。經過上面的錯誤提示,咱們瞭解到-f
的值能夠爲'amd'、'cjs'、'system'、'esm'('es'也能夠)、'iife'或'umd'中的任何一個。-f
參數是--format
的縮寫,它表示生成代碼的格式,amd表示採用AMD標準,cjs爲CommonJS標準,esm(或es)爲ES模塊標準。接着咱們把這段代碼輸出到一個文件中:
$ rollup src/main.js -f es -o dist/bundle.js src/main.js dist/bundle.js... created dist/bundle.js in 29ms 複製代碼
參數-o
指定了輸出的路徑,這裏咱們將打包後的文件輸出到dist目錄下的bundle.js,這個文件內容與咱們以前預覽的內容是徹底一致的。咱們再輸出一份CommonJS格式的代碼:
$ rollup src/main.js --format cjs --output.file dist/bundle-cjs.js src/main.js dist/bundle-cjs.js... created dist/bundle-cjs.js in 27ms 複製代碼
參數--output.file
是-o
的全稱,它們是等價的,輸出後咱們在dist目錄下會多一個bundle-cjs.js文件,查看這個文件的內容:
'use strict'; const a = 1; function main() { console.log(a); } module.exports = main; 複製代碼
能夠看到代碼採用CommonJS標準編寫,而且將a.js和main.js兩個文件進行了融合。
在打包成功後,咱們嘗試運行dist/bundle-cjs.js代碼:
$ node > const m = require('./dist/bundle-cjs.js') > m() 1 複製代碼
咱們接着嘗試運行以前輸出的ES標準代碼dist/bundle.js,因爲nodejs並不支持ES標準,直接運行會報錯:
$ node > require('./dist/bundle.js')() /Users/sam/Desktop/rollup-test/dist/bundle.js:7 export default main; ^^^^^^ SyntaxError: Unexpected token export 複製代碼
babel爲咱們提供了一個工具:babel-node,它能夠在運行時將ES標準的代碼轉換爲CommonJS格式,從而使得運行ES標準的代碼成爲可能,首先全局安裝babel-node及相關工具,@babel/node包含babel-node,@babel/cli包含babel,而這兩個工具都依賴@babel/core,因此建議都安裝:
npm i @babel/core @babel/node @babel/cli -g
複製代碼
這裏要注意的是babel 7改變了npm包的名稱,以前的babel-core和babel-cli已經被棄用,因此安裝老版本babel的同窗建議先卸載:
npm uninstall babel-cli babel-core -g
複製代碼
而後到代碼的根目錄下,初始化項目:
npm init
複製代碼
一路回車後,在代碼根目錄下建立babel的配置文件.babelrc,寫入以下配置
{ "presets": ["@babel/preset-env"] } 複製代碼
完成babel配置後安裝babel的依賴:
npm i -D @babel/core @babel/preset-env
複製代碼
嘗試經過babel編譯代碼:
$ babel dist/bundle.js "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var a = 1; function main() { console.log(a); } var _default = main; exports.default = _default; 複製代碼
能夠看到ES模塊代碼被編譯成了CommonJS格式,下面經過babel-node運行代碼:
$ babel-node > require('./dist/bundle.js') { default: [Function: main] } > require('./dist/bundle.js').default() 1 複製代碼
注意babel會認爲export default function()
是一個名稱爲default的函數,若是想更改這個函數名稱,能夠修改main.js:
import a from './a.js' export function test() { console.log(a) } 複製代碼
重寫打包後經過babel-node運行:
$ rollup -f es --file dist/bundle.js src/main.js src/main.js dist/bundle.js... created dist/bundle.js in 26ms $ babel-node > require('./dist/bundle.js').test() 1 複製代碼
注意這裏的--file
訂價於-o
和--output.file
,經過上述案例,咱們完成了rollup打包的基本操做,並驗證了打包結果。但不少時候咱們不會這樣操做,由於直接使用命令行功能單一,並且沒法使用插件,因此咱們須要藉助配置文件來操做。
首先在代碼根目錄下建立rollup.config.js文件:
touch rollup.config.js
複製代碼
寫入以下配置:
export default { input: './src/main.js', output: [{ file: './dist/index-cjs.js', format: 'cjs', banner: '// welcome to imooc.com', footer: '// powered by sam' }, { file: './dist/index-es.js', format: 'es', banner: '// welcome to imooc.com', footer: '// powered by sam' }] } 複製代碼
rollup的配置文件很是容易理解,這裏有幾點須要說明:
經過rollup -c
指令進行打包,rollup.js會自動尋找名稱爲rollup.config.js的配置文件:
$ rollup -c ./src/main.js ./dist/index-cjs.js, ./dist/index-es.js... created ./dist/index-cjs.js, ./dist/index-es.js in 13ms 複製代碼
查看dist/index-es.js文件:
// welcome to imooc.com const a = 1; function test() { console.log(a); } export { test }; // powered by sam 複製代碼
代碼的內容與命令行生成的無異,但頭部和末尾添加了自定義的註釋信息。接着咱們修改配置文件的名稱,並經過-c
參數指定配置文件進行打包:
$ mv rollup.config.js rollup.config.dev.js $ rollup -c rollup.config.dev.js ./src/main.js ./dist/index-cjs.js, ./dist/index-es.js... created ./dist/index-cjs.js, ./dist/index-es.js in 13ms 複製代碼
不少時候命令行和配置文件的打包方式沒法知足需求,咱們須要更加個性化的打包方式,這時咱們能夠考慮經過rollup.js的api進行打包,建立rollup-input-options.js,這是輸入配置,咱們單獨封裝一個模塊,提升複用性和可擴展性:
touch rollup-input-options.js
複製代碼
在輸入配置文件中加入如下內容,須要注意的是這個文件必須爲CommonJS格式,由於須要使用nodejs來執行:
module.exports = { input: './src/main.js' } 複製代碼
再添加一個輸出配置文件:
touch rollup-output-options.js
複製代碼
在輸出配置文件咱們仍然使用一個數組,實現多種文件格式的輸出,須要注意的是umd格式必須指定模塊的名稱,經過name屬性來實現:
module.exports = [{ file: './dist/index-cjs.js', format: 'cjs', banner: '// welcome to imooc.com', footer: '// powered by sam' }, { file: './dist/index-es.js', format: 'es', banner: '// welcome to imooc.com', footer: '// powered by sam', }, { file: './dist/index-amd.js', format: 'amd', banner: '// welcome to imooc.com', footer: '// powered by sam', }, { file: './dist/index-umd.js', format: 'umd', name: 'sam-umd', // 指定文件名稱 banner: '// welcome to imooc.com', footer: '// powered by sam', }] 複製代碼
接下來咱們要在當前項目中安裝rollup庫:
npm i -D rollup
複製代碼
建立一個rollup-build文件,經過這個文件來調用rollup的api:
touch rollup-build.js
複製代碼
rollup-build的源碼以下:
const rollup = require('rollup') const inputOptions = require('./rollup-input-options') const outputOptions = require('./rollup-output-options') async function rollupBuild(input, output) { const bundle = await rollup.rollup(input) // 根據input配置進行打包 console.log(`正在生成:${output.file}`) await bundle.write(output) // 根據output配置輸出文件 console.log(`${output.file}生成成功!`) } (async function () { for (let i = 0; i < outputOptions.length; i++) { await rollupBuild(inputOptions, outputOptions[i]) } })() 複製代碼
代碼的核心有兩點:
rollup.rollup(input)
獲得打包對象bundle.write(output)
輸出打包文件這裏咱們還能夠經過async和await實現同步操做,由於bundle.write(output)
是異步的,會返回Promise對象,咱們能夠藉助async機制實現按配置順序依次打包。執行rollup-build文件:
$ node rollup-build.js
正在生成:./dist/index-cjs.js
./dist/index-cjs.js生成成功!
正在生成:./dist/index-es.js
./dist/index-es.js生成成功!
正在生成:./dist/index-amd.js
./dist/index-amd.js生成成功!
正在生成:./dist/index-umd.js
./dist/index-umd.js生成成功!
複製代碼
查看dist/index-umd.js文件:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global['sam-umd'] = {}))); }(this, (function (exports) { // ... } 複製代碼
能夠看到index-umd.js文件中在global全局變量中添加了sam-umd屬性,這就是咱們以前須要在umd配置中添加name屬性的緣由。
本文向你們介紹了rollup.js的三種打包方式:命令行、配置文件和API,在下一篇教程中我將繼續爲你們介紹更多rollup.js的特性,如Tree-shaking、watch等,還會詳細演示各類插件的用途及用法,敬請關注。