前言
項目中一直用的都是webpack
,前一段須要開發幾個類庫供其餘平臺使用,原本打算繼續用webpack
的,但感受webpack
用來開發js
庫,不只繁瑣並且打包後的文件體積也比較大。正好以前看vue
源碼,知道vue
也是經過rollup
打包的。此次又是開發類庫的,因而就快速上手了rollup
。html
本篇文章是我有了必定的項目實踐後,回過來給你們分享一下如何從零快速上手rollup
。前端
什麼是rollup
?
系統的瞭解rollup
以前,咱們先來簡單瞭解下What is rollup?
vue
關於rollup
的介紹,官方文檔已經寫的很清楚了:node
Rollup 是一個 JavaScript 模塊打包器,能夠將小塊代碼編譯成大塊複雜的代碼,例如 library 或應用程序。webpack
與Webpack
偏向於應用打包的定位不一樣,rollup.js
更專一於Javascript
類庫打包。es6
咱們熟知的Vue
、React
等諸多知名框架或類庫都是經過rollup.js
進行打包的。web
爲何是rollup
?
webpack
我相信作前端的同窗你們都用過,那麼爲何有些場景還要使用rollup
呢?這裏我簡單對webpack
和rollup
作一個比較:面試
整體來講webpack
和rollup
在不一樣場景下,都能發揮自身優點做用。webpack
對於代碼分割和靜態資源導入有着「先天優點」,而且支持熱模塊替換(HMR
),而rollup
並不支持。算法
因此當開發應用時能夠優先選擇webpack
,可是rollup
對於代碼的Tree-shaking
和ES6
模塊有着算法優點上的支持,若你項目只須要打包出一個簡單的bundle
包,並是基於ES6
模塊開發的,能夠考慮使用rollup
。npm
其實webpack
從2.0
開始就已經支持Tree-shaking
,並在使用babel-loader
的狀況下還能夠支持es6 module
的打包。實際上,rollup
已經在漸漸地失去了當初的優點了。可是它並無被拋棄,反而因其簡單的API
、使用方式被許多庫開發者青睞,如React
、Vue
等,都是使用rollup
做爲構建工具的。
快速上手
咱們先花大概十分鐘左右的時間來了解下rollup
的基本使用以及完成一個hello world
。
安裝
首先全局安裝rollup
:
npm i rollup -g
目錄準備(hello world)
接着,咱們初始化一個以下所示的項目目錄
├── dist # 編譯結果
├── example # HTML引用例子
│ └── index.html
├── package.json
└── src # 源碼
└── index.js
首先咱們在src/index.js
中寫入以下代碼:
console.log("柯森");
而後在命令行執行如下命令:
rollup src/index.js -f umd -o dist/bundle.js
執行命令,咱們便可在dist
目錄下生成bundle.js
文件:
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
}((function () { 'use strict';
console.log("柯森");
})));
這時,咱們再在example/index.html
中引入上面打包生成的bundle.js
文件,打開瀏覽器:如咱們所預料的,控制檯輸出了
柯森
。
到這裏,咱們就用rollup
打包了一個最最簡單的demo
。
可能不少同窗看到這裏對於上面命令行中的參數不是很明白,我依次說明下:
-
-f
。-f
參數是--format
的縮寫,它表示生成代碼的格式,amd
表示採用AMD
標準,cjs
爲CommonJS
標準,esm
(或 es)爲ES
模塊標準。-f
的值能夠爲amd
、cjs
、system
、esm
('es’也能夠)、iife
或umd
中的任何一個。 -
-o
。-o
指定了輸出的路徑,這裏咱們將打包後的文件輸出到dist
目錄下的bundle.js
其實除了這兩個,還有不少其餘經常使用的命令(這裏我暫且列舉剩下兩個也比較經常使用的,完整的rollup 命令行參數):
-
-c
。指定rollup
的配置文件。 -
-w
。監聽源文件是否有改動,若是有改動,從新打包。
使用配置文件(rollup.config.js
)
使用命令行的方式,若是選項少沒什麼問題,可是若是添加更多的選項,這種命令行的方式就顯得麻煩了。
爲此,咱們能夠建立配置文件來囊括所需的選項
在項目中建立一個名爲rollup.config.js
的文件,增長以下代碼:
export default {
input: ["./src/index.js"],
output: {
file: "./dist/bundle.js",
format: "umd",
name: "experience",
},
};
而後命令行執行:
rollup -c
打開dist/bundle.js
文件,咱們會發現和上面採用命令行的方式打包出來的結果是同樣的。
這裏,我對配置文件的選項作下簡單的說明:
-
input
表示入口文件的路徑(老版本爲 entry,已經廢棄) -
output
表示輸出文件的內容,它容許傳入一個對象或一個數組,當爲數組時,依次輸出多個文件,它包含如下內容: -
output.file
:輸出文件的路徑(老版本爲 dest,已經廢棄) -
output.format
:輸出文件的格式 -
output.banner
:文件頭部添加的內容 -
output.footer
:文件末尾添加的內容
到這裏,相信你已經差很少上手rollup
了。
進階
可是,這對於真實的業務場景是遠遠不夠的。
下面,我將介紹rollup
中的幾種經常使用的插件以及external
屬性、tree-shaking
機制。
resolve
插件
爲何要使用resolve
插件
在上面的入門案例中,咱們打包的對象是本地的js
代碼和庫,但實際開發中,不太可能全部的庫都位於本地,咱們大多會經過npm
下載遠程的庫。
與webpack
和browserify
這樣的其餘捆綁包不一樣,rollup
不知道如何打破常規去處理這些依賴。所以咱們須要添加一些配置。
resolve
插件使用
首先在咱們的項目中添加一個依賴the-answer
,而後修改src/index.js
文件:
import answer from "the-answer";
export default function () {
console.log("the answer is " + answer);
}
執行npm run build
。
這裏爲了方便,我將本來的
rollup -c -w
添加到了package.json
的scripts
中:"build": "rollup -c -w"
會獲得如下報錯:打包後的
bundle.js
仍然會在Node.js
中工做,可是the-answer
不包含在包中。爲了解決這個問題,將咱們編寫的源碼與依賴的第三方庫進行合併,rollup.js
爲咱們提供了resolve
插件。
首先,安裝resolve
插件:
npm i -D @rollup/plugin-node-resolve
修改配置文件rollup.config.js
:
import resolve from "@rollup/plugin-node-resolve";
export default {
input: ["./src/index.js"],
output: {
file: "./dist/bundle.js",
format: "umd",
name: "experience",
},
plugins: [resolve()],
};
這時再次執行npm run build
,能夠發現報錯已經沒有了:
打開dist/bundle.js
文件:
(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.experience = factory());
}(this, (function () { 'use strict';
var index = 42;
function index$1 () {
console.log("the answer is " + index);
}
return index$1;
})));
打包文件bundle.js
中已經包含了引用的模塊。
有些場景下,雖然咱們使用了resolve
插件,但可能咱們仍然想要某些庫保持外部引用狀態,這時咱們就須要使用external
屬性,來告訴rollup.js
哪些是外部的類庫。
external 屬性
修改rollup.js
的配置文件:
import resolve from "@rollup/plugin-node-resolve";
export default {
input: ["./src/index.js"],
output: {
file: "./dist/bundle.js",
format: "umd",
name: "experience",
},
plugins: [resolve()],
external: ["the-answer"],
};
從新打包,打開dist/bundle.js
文件:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('the-answer')) :
typeof define === 'function' && define.amd ? define(['the-answer'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory(global.answer));
}(this, (function (answer) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var answer__default = /*#__PURE__*/_interopDefaultLegacy(answer);
function index () {
console.log("the answer is " + answer__default['default']);
}
return index;
})));
這時咱們看到the-answer
已是作爲外部庫被引入了。
commonjs
插件
爲何須要commonjs
插件
rollup.js
編譯源碼中的模塊引用默認只支持 ES6+
的模塊方式import/export
。然而大量的npm
模塊是基於CommonJS
模塊方式,這就致使了大量 npm
模塊不能直接編譯使用。
所以使得rollup.js
編譯支持npm
模塊和CommonJS
模塊方式的插件就應運而生:@rollup/plugin-commonjs
。
commonjs
插件使用
首先,安裝該模塊:
npm i -D @rollup/plugin-commonjs
而後修改rollup.config.js
文件:
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
export default {
input: ["./src/index.js"],
output: {
file: "./dist/bundle.js",
format: "umd",
name: "experience",
},
plugins: [resolve(), commonjs()],
external: ["the-answer"],
};
babel
插件
爲何須要babel
插件?
咱們在src
目錄下添加es6.js
文件(⚠️ 這裏咱們使用了 es6 中的箭頭函數):
const a = 1;
const b = 2;
console.log(a, b);
export default () => {
return a + b;
};
而後修改rollup.config.js
配置文件:
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
export default {
input: ["./src/es6.js"],
output: {
file: "./dist/esBundle.js",
format: "umd",
name: "experience",
},
plugins: [resolve(), commonjs()],
external: ["the-answer"],
};
執行打包,能夠看到dist/esBundle.js
文件內容以下:
(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.experience = factory());
}(this, (function () { 'use strict';
const a = 1;
const b = 2;
console.log(a, b);
var es6 = () => {
return a + b;
};
return es6;
})));
能夠看到箭頭函數被保留下來,這樣的代碼在不支持ES6
的環境下將沒法運行。咱們指望在rollup.js
打包的過程當中就能使用babel
完成代碼轉換,所以咱們須要babel
插件。
babel
插件的使用
首先,安裝:
npm i -D @rollup/plugin-babel
一樣修改配置文件rollup.config.js
:
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import babel from "@rollup/plugin-babel";
export default {
input: ["./src/es6.js"],
output: {
file: "./dist/esBundle.js",
format: "umd",
name: "experience",
},
plugins: [resolve(), commonjs(), babel()],
external: ["the-answer"],
};
而後打包,發現會出現報錯:提示咱們缺乏
@babel/core
,由於@babel/core
是babel
的核心。咱們來進行安裝:
npm i @babel/core
再次執行打包,發現此次沒有報錯了,可是咱們嘗試打開dist/esBundle.js
:
(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.experience = factory());
}(this, (function () { 'use strict';
const a = 1;
const b = 2;
console.log(a, b);
var es6 = (() => {
return a + b;
});
return es6;
})));
能夠發現箭頭函數仍然存在,顯然這是不正確的,說明咱們的babel
插件沒有起到做用。這是爲何呢?
緣由是因爲咱們缺乏.babelrc
文件,添加該文件:
{
"presets": [
[
"@babel/preset-env",
{
"modules": false,
// "useBuiltIns": "usage"
}
]
]
}
咱們看.babelrc
配置了preset env
,因此先安裝這個插件:
npm i @babel/preset-env
此次再次執行打包,咱們打開dist/esBundle.js
文件:
(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.experience = factory());
}(this, (function () { 'use strict';
var a = 1;
var b = 2;
console.log(a, b);
var es6 = (function () {
return a + b;
});
return es6;
})));
能夠看到箭頭函數被轉換爲了function
,說明babel
插件正常工做。
json
插件
爲何要使用json
插件?
在src
目錄下建立json.js
文件:
import json from "../package.json";
console.log(json.author);
內容很簡單,就是引入package.json
,而後去打印author
字段。
修改rollup.config.js
配置文件:
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import babel from "@rollup/plugin-babel";
export default {
input: ["./src/json.js"],
output: {
file: "./dist/jsonBundle.js",
format: "umd",
name: "experience",
},
plugins: [resolve(), commonjs(), babel()],
external: ["the-answer"],
};
執行打包,發現會發生以下報錯:提示咱們缺乏
@rollup/plugin-json
插件來支持json
文件。
json
插件的使用
來安裝該插件:
npm i -D @rollup/plugin-json
一樣修改下配置文件,將插件加入plugins
數組便可。
而後再次打包,發現打包成功了,咱們打開生成的dist/jsonBundle
目錄:
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
}((function () { 'use strict';
var name = "rollup-experience";
var version = "1.0.0";
var description = "";
var main = "index.js";
var directories = {
example: "example"
};
var scripts = {
build: "rollup -c -w",
test: "echo \"Error: no test specified\" && exit 1"
};
var author = "Cosen";
var license = "ISC";
var dependencies = {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"the-answer": "^1.0.0"
};
var devDependencies = {
"@rollup/plugin-babel": "^5.2.0",
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^9.0.0"
};
var json = {
name: name,
version: version,
description: description,
main: main,
directories: directories,
scripts: scripts,
author: author,
license: license,
dependencies: dependencies,
devDependencies: devDependencies
};
console.log(json.author);
})));
完美!!
tree-shaking
機制
這裏咱們以最開始的src/index.js
爲例進行說明:
import answer from "the-answer";
export default function () {
console.log("the answer is " + answer);
}
修改上述文件:
const a = 1;
const b = 2;
export default function () {
console.log(a + b);
}
執行打包。打開dist/bundle.js
文件:
(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.experience = factory());
}(this, (function () { 'use strict';
var a = 1;
var b = 2;
function index () {
console.log(a + b);
}
return index;
})));
再次修改src/index.js
文件:
const a = 1;
const b = 2;
export default function () {
console.log(a);
}
再次執行打包,打開打包文件:
(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.experience = factory());
}(this, (function () { 'use strict';
var a = 1;
function index () {
console.log(a);
}
return index;
})));
發現了什麼?
咱們發現關於變量b
的定義沒有了,由於源碼中並無用到這個變量。這就是ES
模塊著名的tree-shaking
機制,它動態地清除沒有被使用過的代碼,使得代碼更加精簡,從而可使得咱們的類庫得到更快的加載速度。
總結
本文大體向你們介紹了什麼是rollup
以及如何快速上手rollup
。文中提到的這些其實只是冰山一角,rollup
能玩的東西還有不少,關於更多能夠去rollup 官網查詢
關注我
我是山月,正致力於天天用五分鐘可以看完的簡短答案回答一個大廠高頻面試題。掃碼添加個人微信,備註進羣,加入高級前端進階羣.
![](http://static.javashuo.com/static/loading.gif)
歡迎關注公衆號【互聯網大廠招聘】,定時推送大廠內推信息及面試題簡答,天天學習五分鐘,半年進入大廠中
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - 全棧成長之路(shanyue-road)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。