一篇文章帶你從零快速上手Rollup
前言
項(xiàng)目中一直用的都是webpack,前一段需要開發(fā)幾個(gè)類庫供其他平臺(tái)使用,本來打算繼續(xù)用webpack的,但感覺webpack用來開發(fā)js庫,不僅繁瑣而且打包后的文件體積也比較大。正好之前看vue源碼,知道vue也是通過rollup打包的。這次又是開發(fā)類庫的,于是就快速上手了rollup。
本篇文章是我有了一定的項(xiàng)目實(shí)踐后,回過來給大家分享一下如何從零快速上手rollup。
什么是rollup?
系統(tǒng)的了解rollup之前,我們先來簡(jiǎn)單了解下What is rollup?
關(guān)于rollup的介紹,官方文檔已經(jīng)寫的很清楚了:
Rollup 是一個(gè) JavaScript 模塊打包器,可以將小塊代碼編譯成大塊復(fù)雜的代碼,例如 library 或應(yīng)用程序。
與Webpack偏向于應(yīng)用打包的定位不同,rollup.js更專注于Javascript類庫打包。
我們熟知的Vue、React等諸多知名框架或類庫都是通過rollup.js進(jìn)行打包的。
為什么是rollup?
webpack我相信做前端的同學(xué)大家都用過,那么為什么有些場(chǎng)景還要使用rollup呢?這里我簡(jiǎn)單對(duì)webpack和rollup做一個(gè)比較:
總體來說webpack和rollup在不同場(chǎng)景下,都能發(fā)揮自身優(yōu)勢(shì)作用。webpack對(duì)于代碼分割和靜態(tài)資源導(dǎo)入有著“先天優(yōu)勢(shì)”,并且支持熱模塊替換(HMR),而rollup并不支持。
所以當(dāng)開發(fā)應(yīng)用時(shí)可以優(yōu)先選擇webpack,但是rollup對(duì)于代碼的Tree-shaking和ES6模塊有著算法優(yōu)勢(shì)上的支持,若你項(xiàng)目只需要打包出一個(gè)簡(jiǎn)單的bundle包,并是基于ES6模塊開發(fā)的,可以考慮使用rollup。
其實(shí)webpack從2.0開始就已經(jīng)支持Tree-shaking,并在使用babel-loader的情況下還可以支持es6 module的打包。實(shí)際上,rollup已經(jīng)在漸漸地失去了當(dāng)初的優(yōu)勢(shì)了。但是它并沒有被拋棄,反而因其簡(jiǎn)單的API、使用方式被許多庫開發(fā)者青睞,如React、Vue等,都是使用rollup作為構(gòu)建工具的。
快速上手
我們先花大概十分鐘左右的時(shí)間來了解下rollup的基本使用以及完成一個(gè)hello world。
安裝
首先全局安裝rollup:
npm i rollup -g
目錄準(zhǔn)備(hello world)
接著,我們初始化一個(gè)如下所示的項(xiàng)目目錄
├── dist # 編譯結(jié)果
├── example # HTML引用例子
│ └── index.html
├── package.json
└── src # 源碼
└── index.js
首先我們?cè)趕rc/index.js中寫入如下代碼:
console.log("柯森");
然后在命令行執(zhí)行以下命令:
rollup src/index.js -f umd -o dist/bundle.js
執(zhí)行命令,我們即可在dist目錄下生成bundle.js文件:
(function (factory) { typeof define === 'function' && define.amd ? define(factory) : factory(); }((function () { 'use strict'; console.log("柯森"); })));
這時(shí),我們?cè)僭趀xample/index.html中引入上面打包生成的bundle.js文件,打開瀏覽器:
如我們所預(yù)料的,控制臺(tái)輸出了柯森。
到這里,我們就用rollup打包了一個(gè)最最簡(jiǎn)單的demo。
可能很多同學(xué)看到這里對(duì)于上面命令行中的參數(shù)不是很明白,我依次說明下:
- -f。-f參數(shù)是--format的縮寫,它表示生成代碼的格式,amd表示采用AMD標(biāo)準(zhǔn),cjs為CommonJS標(biāo)準(zhǔn),esm(或 es)為ES模塊標(biāo)準(zhǔn)。-f的值可以為amd、cjs、system、esm('es'也可以)、iife或umd中的任何一個(gè)。
- -o。-o指定了輸出的路徑,這里我們將打包后的文件輸出到dist目錄下的bundle.js
其實(shí)除了這兩個(gè),還有很多其他常用的命令(這里我暫且列舉剩下兩個(gè)也比較常用的,完整的rollup 命令行參數(shù)):
- -c。指定rollup的配置文件。
- -w。監(jiān)聽源文件是否有改動(dòng),如果有改動(dòng),重新打包。
使用配置文件(rollup.config.js)
使用命令行的方式,如果選項(xiàng)少?zèng)]什么問題,但是如果添加更多的選項(xiàng),這種命令行的方式就顯得麻煩了。
為此,我們可以創(chuàng)建配置文件來囊括所需的選項(xiàng)
在項(xiàng)目中創(chuàng)建一個(gè)名為rollup.config.js的文件,增加如下代碼:
export default { input: ["./src/index.js"], output: { file: "./dist/bundle.js", format: "umd", name: "experience", }, };
然后命令行執(zhí)行:
rollup -c
打開dist/bundle.js文件,我們會(huì)發(fā)現(xiàn)和上面采用命令行的方式打包出來的結(jié)果是一樣的。
這里,我對(duì)配置文件的選項(xiàng)做下簡(jiǎn)單的說明:
- input表示入口文件的路徑(老版本為 entry,已經(jīng)廢棄)
- output表示輸出文件的內(nèi)容,它允許傳入一個(gè)對(duì)象或一個(gè)數(shù)組,當(dāng)為數(shù)組時(shí),依次輸出多個(gè)文件,它包含以下內(nèi)容:
- output.file:輸出文件的路徑(老版本為 dest,已經(jīng)廢棄)
- output.format:輸出文件的格式
- output.banner:文件頭部添加的內(nèi)容
- output.footer:文件末尾添加的內(nèi)容
到這里,相信你已經(jīng)差不多上手rollup了。
進(jìn)階
但是,這對(duì)于真實(shí)的業(yè)務(wù)場(chǎng)景是遠(yuǎn)遠(yuǎn)不夠的。
下面,我將介紹rollup中的幾種常用的插件以及external屬性、tree-shaking機(jī)制。
resolve插件
為什么要使用resolve插件
在上面的入門案例中,我們打包的對(duì)象是本地的js代碼和庫,但實(shí)際開發(fā)中,不太可能所有的庫都位于本地,我們大多會(huì)通過npm下載遠(yuǎn)程的庫。
與webpack和browserify這樣的其他捆綁包不同,rollup不知道如何打破常規(guī)去處理這些依賴。因此我們需要添加一些配置。
resolve插件使用
首先在我們的項(xiàng)目中添加一個(gè)依賴the-answer,然后修改src/index.js文件:
import answer from "the-answer"; export default function () { console.log("the answer is " + answer); }
執(zhí)行npm run build
。
這里為了方便,我將原本的rollup -c -w添加到了package.json的scripts中:"build": "rollup -c -w"
會(huì)得到以下報(bào)錯(cuò):
打包后的bundle.js仍然會(huì)在Node.js中工作,但是the-answer不包含在包中。為了解決這個(gè)問題,將我們編寫的源碼與依賴的第三方庫進(jìn)行合并,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()], };
這時(shí)再次執(zhí)行npm run build,可以發(fā)現(xiàn)報(bào)錯(cuò)已經(jīng)沒有了:
打開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中已經(jīng)包含了引用的模塊。
有些場(chǎng)景下,雖然我們使用了resolve插件,但可能我們?nèi)匀幌胍承毂3滞獠恳脿顟B(tài),這時(shí)我們就需要使用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; })));
這時(shí)我們看到the-answer已經(jīng)是做為外部庫被引入了。
commonjs插件
為什么需要commonjs插件
rollup.js編譯源碼中的模塊引用默認(rèn)只支持 ES6+的模塊方式import/export。然而大量的npm模塊是基于CommonJS模塊方式,這就導(dǎo)致了大量 npm模塊不能直接編譯使用。
因此使得rollup.js編譯支持npm模塊和CommonJS模塊方式的插件就應(yīng)運(yùn)而生:@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插件?
我們?cè)趕rc目錄下添加es6.js文件(⚠️ 這里我們使用了 es6 中的箭頭函數(shù)):
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"], };
執(zhí)行打包,可以看到dist/esBundle.js文件內(nèi)容如下:
(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; })));
可以看到箭頭函數(shù)被保留下來,這樣的代碼在不支持ES6的環(huán)境下將無法運(yùn)行。我們期望在rollup.js打包的過程中就能使用babel完成代碼轉(zhuǎn)換,因此我們需要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"], };
然后打包,發(fā)現(xiàn)會(huì)出現(xiàn)報(bào)錯(cuò):
提示我們?nèi)鄙貮babel/core,因?yàn)锧babel/core是babel的核心。我們來進(jìn)行安裝:
npm i @babel/core
再次執(zhí)行打包,發(fā)現(xiàn)這次沒有報(bào)錯(cuò)了,但是我們嘗試打開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; })));
可以發(fā)現(xiàn)箭頭函數(shù)仍然存在,顯然這是不正確的,說明我們的babel插件沒有起到作用。這是為什么呢?
原因是由于我們?nèi)鄙?babelrc文件,添加該文件:
{ "presets": [ [ "@babel/preset-env", { "modules": false, // "useBuiltIns": "usage" } ] ] }
我們看.babelrc配置了preset env,所以先安裝這個(gè)插件:
npm i @babel/preset-env
這次再次執(zhí)行打包,我們打開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; })));
可以看到箭頭函數(shù)被轉(zhuǎn)換為了function,說明babel插件正常工作。
json插件
為什么要使用json插件?
在src目錄下創(chuàng)建json.js文件:
import json from "../package.json"; console.log(json.author);
內(nèi)容很簡(jiǎn)單,就是引入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"], };
執(zhí)行打包,發(fā)現(xiàn)會(huì)發(fā)生如下報(bào)錯(cuò):
提示我們?nèi)鄙貮rollup/plugin-json插件來支持json文件。
json插件的使用
來安裝該插件:
npm i -D @rollup/plugin-json
同樣修改下配置文件,將插件加入plugins數(shù)組即可。
然后再次打包,發(fā)現(xiàn)打包成功了,我們打開生成的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); })));
完美?。?/p>
tree-shaking機(jī)制
這里我們以最開始的src/index.js為例進(jìn)行說明:
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); }
執(zhí)行打包。打開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); }
再次執(zhí)行打包,打開打包文件:
(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; })));
發(fā)現(xiàn)了什么?
我們發(fā)現(xiàn)關(guān)于變量b的定義沒有了,因?yàn)樵创a中并沒有用到這個(gè)變量。這就是ES模塊著名的tree-shaking機(jī)制,它動(dòng)態(tài)地清除沒有被使用過的代碼,使得代碼更加精簡(jiǎn),從而可以使得我們的類庫獲得更快的加載速度。
總結(jié)
本文大致向大家介紹了什么是rollup以及如何快速上手rollup。文中提到的這些其實(shí)只是冰山一角,rollup能玩的東西還有很多,關(guān)于更多可以去rollup 官網(wǎng)查詢
到此這篇帶你從零快速上手Rollup的文章就介紹到這了,更多相關(guān)從零快速上手Rollup內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
動(dòng)態(tài)添加option及createElement使用示例
動(dòng)態(tài)添加option在某些特殊的情況下還是比較實(shí)用的,本文有個(gè)小示例為大家介紹下createElement使用,感興趣的朋友可以參考下2014-01-01分享一個(gè)自己寫的table表格排序js插件(高效簡(jiǎn)潔)
在前不久做的一個(gè)web項(xiàng)目中,需要實(shí)現(xiàn)js表格排序的效果,當(dāng)時(shí)為了省事,就在網(wǎng)上找了幾個(gè)相關(guān)的js插件2011-10-10QQ跳轉(zhuǎn)支付寶并自動(dòng)領(lǐng)紅包腳本(最新)
這篇文章主要給大家分享介紹了一個(gè)QQ跳轉(zhuǎn)支付寶并自動(dòng)領(lǐng)紅包腳本,這個(gè)腳本應(yīng)該是最新的,測(cè)試后是可以使用的,文中給出了完整的示例代碼和使用方法,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06js 右鍵菜單,支持不同對(duì)象不同菜單(兼容IE、Firefox)
版本雖然很老也不符合標(biāo)準(zhǔn)了,不過代碼是值得參考的,需要右鍵菜單的朋友可以參考下。2010-01-01js實(shí)現(xiàn)網(wǎng)頁多級(jí)級(jí)聯(lián)菜單代碼
這篇文章主要介紹了js實(shí)現(xiàn)網(wǎng)頁多級(jí)級(jí)聯(lián)菜單代碼,涉及javascript基于數(shù)組動(dòng)態(tài)構(gòu)造多級(jí)級(jí)聯(lián)菜單的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-08-08