10分鐘快速入門rollup.js

爲何要學習rollup.js

rollup.js是Javascript的ES模塊打包器,咱們熟知的Vue、React等諸多知名框架或類庫都經過rollup.js進行打包。與Webpack偏向於應用打包的定位不一樣,rollup.js更專一於Javascript類庫打包(雖然rollup.js也能夠提供資源打包,但顯然這不是它的強項)。在咱們學習Vue和React等框架源碼或者本身編寫Javascript類庫時,rollup.js是一條必經之路。javascript

rollup.js的工做原理

rollup.js能夠將咱們本身編寫的Javascript代碼(經過插件能夠支持更多語言,如Tyepscript)與第三方模塊打包在一塊兒,造成一個文件,該文件能夠是一個庫(Library)或者一個應用(App),在打包過程當中能夠應用各種插件實現特定功能。下圖揭示了rollup.js的運行機制: java

rollup.js運行機制
rollup.js默認採用ES模塊標準,咱們能夠經過rollup-plugin-commonjs插件使之支持CommonJS標準。

安裝rollup.js

rollup.js的安裝依賴於nodejs,以前的手記中我曾詳細介紹如何經過nvm管理nodejs版本,須要瞭解的小夥伴能夠點擊這裏node

全局安裝rollup.js

首先全局安裝rollup:npm

npm i rollup -g
複製代碼

rollup.js打包實例

安裝成功後,咱們嘗試使用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兩個文件進行了融合。

驗證rollup.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.js配置文件

首先在代碼根目錄下建立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的配置文件須要採用ES模塊標準編寫
  • input表示入口文件的路徑(老版本爲entry,已經廢棄)
  • output表示輸出文件的內容,它容許傳入一個對象或一個數組,當爲數組時,依次輸出多個文件,它包含如下內容:
    • output.file:輸出文件的路徑(老版本爲dest,已經廢棄)
    • output.format:輸出文件的格式
    • output.banner:文件頭部添加的內容
    • output.footer:文件末尾添加的內容

經過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.js配置

不少時候命令行和配置文件的打包方式沒法知足需求,咱們須要更加個性化的打包方式,這時咱們能夠考慮經過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.js build代碼

接下來咱們要在當前項目中安裝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等,還會詳細演示各類插件的用途及用法,敬請關注。

相關文章
相關標籤/搜索