webpack實戰——JS打包工具

前言

前面篇章敘述了關於webpack的許多內容,從入門,打包第一個模塊,到進階,最後到本地、生產及打包的優化。本篇則提及一下在JavaScript社區中另外的一些類似的打包工具,它們有的更加輕量、簡潔,有的則更專注於某類特定場景等。通過了解這些,希望會有助於我們開發時從更多的角度和方向來認識打包工具及其發展,進而選用更加適合我們項目的打包工具。

1. Rollup

Rollup專注於JavaScript的打包。

它當然也支持其他類型的模塊,但是總體而言在通用性是不及webpack,但討論專注性,Rollup則更像一把手術刀,能精準的瞄準於JavaScript。如果有項目需求僅僅是打包JavaScript,那麼Rollup則更可能是我們的第一選擇。

1.1 配置

簡單示例下Rollup是如何工作的。

首先全局安裝Rollup

npm install rollup -g

然後創建Rollup配置文件rollup.config.js以及需要打包的項目文件app.js

// rollup.config.js
module exports = {
    input: 'src/app.js',
    output: {
        file: 'dist/bundle.js',
        format: 'cjs'
    }
}
// src/app.js
console.log('This is a App with Rollup ~');

接下來執行指令進行打包:

rollup -c rollup.config.js

其中,-c參數是告訴Rollup使用該配置文件。

打包結果如下:

'use strict';
console.log('This is a App with Rollup ~');

從上可以看出,打包出來的資源文件非常乾淨,Rollup沒有添加額外代碼,甚至連第一行的use strict都可以通過配置去掉。而如果我們使用webpack去打包處理,則會多出許多冗餘產物,即使我們將上述的一行js進行打包,打包後資源文件也至少會有幾十行代碼存在。

顯然,如果針對於JavaScript進行打包處理,Rollup更爲符合我們的預期。

1.2 tree shaking

上一篇也描述過關於tree shaking,用來檢測和去除死代碼。而實際上最初tree shaking這個特性是由Roolup實現的,然後被Webpack借鑑。

Rollup的tree shaking也是基於ES6 Modules的靜態分析,找出沒有被引用的模塊,將其從最後生成的bundle中排除。

例:

// app.js
import { add } from './util.js';
console.log(`1 + 2 = ${add(1, 2)}`);
// util.js
export function add(a, b) {
    return a + b;
}

export function sub(a, b) {
    return a - b;
}

可以看到,在這個簡單工程中,sub方法沒有被引用。

執行命令對其打包後,發現:

'use strict';

function add(a, b) {
    return a + b;
}

console.log(`1 + 2 = ${add(1, 2)}`);

從打包結果看,bundle也如我們所期望,輸出的內容簡潔,無任何附加代碼,且sub函數也沒有被打包進來。

1.3 可選的輸出格式

在webpack中,無法選擇輸出資源的模塊形式,例如amd、esm、umd、system等,而在Rollup中可以通過配置output.format開發者選擇輸出資源的模塊形式。

這個特性對於打包JavaScript庫很有用,因爲一個庫往往需要支持多種不同的模塊形式,而通過Rollup幾個命令就可以將一份源代碼打包爲多份支持不同模式的資源文件。

例:

'use strict';
export function add(a, b) {
    return a + b;
}
export function sub(a, b) {
    return a - b;
}

當output.format是cjs時(cjs:CommonJs),則輸出是:

Object.defineProperty(exports, '__esModule', {value: true});
function add(a, b) {
    return a + b;
}
function sub(a, b) {
    return a - b;
}
exports.add = add;
exports.sub = sub;

當時esm時(ES6 Modules),輸出則是:

function add(a, b) {
    return a + b;
}
function sub(a, b) {
    return a - b;
}
export { add, sub }

1.4 使用Rollup構建JavaScript庫

在實際使用中,Rollup經常被用於打包一些庫或框架(例如Vue、React等)。在React團隊的一篇文章中曾提到使用Rollup的獲益:

  • 最低限度的附加代碼
  • 對ES6 Modules的良好支持
  • 通過tree shaking去除開發環境代碼
  • 通過自定義插件來實現React的一些特殊的打包邏輯

Rollup在設計之初就是主要偏向於JavaScript庫的構建,以至於它並沒有像Webpack那樣對於應用開發有很大的支持,所以我們使用Rollup之前要斟酌下是否偏向自己的項目需求。

2. Parcel

Parcel在前端打包工具中屬於後起之秀:2017年8月纔在npm上有版本記錄。而其出名的則是打包速度:“Parcel官網中宣稱自己是零配置的,在有緩存的情況下其打包速度比webpack快近8倍。”它的出現,則是正好契合了當時開發者對於Webpack打包速度慢和配置複雜的抱怨,從而吸引許多用戶轉用Parcel。

2.1 打包速度

Parcel在打包速度的優化上主要做了3件事:

  • 利用worker來並行執行任務
  • 文件系統緩存
  • 資源編譯處理流程優化

這三點的前兩點其實Webpack已經在做,在此不再詳細分析。重點看第三點。

例如對於babel-loader的工作流程進行分析,大體爲以下幾步:

  1. 將ES6形式的字符串內容解析爲AST(抽象語法樹);
  2. 對AST進行語法轉換;
  3. 生成ES5代碼,並作爲字符串返回。

這是一個很正常的資源處理過程,但假設是多個loader一次對資源進行處理呢?

對此,Parcel的處理流程很簡單,它並沒有loader的概念,而是自己的一套體系處理:它在不同的編譯處理流程之間可以用AST作爲輸入和輸出,不需要轉換爲字符串處理。對於單個的每一步來說,如果前面已經解析過AST,那麼直接使用上一步解析和轉換好的AST就可以,只需要在最後一步輸出的時候再將AST轉回字符串即可。如此說來,中間的流程處理由多次變爲了一次,能夠節省的時間可不是一星半點!

2.2 零配置

請看例子:

<!-- index.html -->
<html>
<body>
    <script src="./bundle.js"></script>
</body>
</html>
// index.js
document.write('Hello Parcel!');

先全局安裝parcel:

npm install parcel -g

然後執行打包命令:

parcel index.html
// 如果要打包爲文件,則執行如下:
parcel build index.html

如果不加build,則是開發模式,使用瀏覽器則可以觀察:localhost:1234。

如果打包爲文件,則會創建一個dist文件目錄,資源會添加到該目錄下。

其實對於一個正常的前端項目來說,一般都會有一些配置的,不然也就失去了定製性。雖然parcel並沒有配置文件,但是本質上它還是把配置進行了切分,交給babel、postHTML、postCSS等一些特定的工具進行了管理。

與Webpack相比,Parcel優勢在於快速和靈巧,如果針對於不需要深度定製並且要求短時間搭建,那麼Parcel則也可以作爲一個比較好的選擇來作爲備選。

小結

本篇介紹了JavaScript社區中兩個除了webpack之外比較主流的兩個打包工具:Rollup和Parcel。

Rollup更專注於JavaScript的打包,本身附加的代碼更少,具備tree shaking,可以輸出多種形式的模塊。

Parcel則在資源處理流程方面做了改進優化,以追求更快的打包速度。同時零配置的特性可以減少很多項目開發中花費在環境維護上的成本。

在進行技術選型的時候,我們不僅要結合目前工具特性,更是要選擇出針對我們項目進行特定考察,以及對項目之後的擴展也要考慮在內,從而結合多方面選擇對項目最有利的工具來使用。同時我們也要看此工具在社區中的生態,是否能保持良好的社區生態以及維護狀況,亦是我們需要考慮在內的因素之一。

webpack實戰系列內容到此結束~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章