avatar
threadsinstagram

現代 bundler、build tool 簡介

Table of Contents

前言

前面模組化歷史不小心鑽太深,在稍微有點長的前情提要後,今天終於要講回正題了。

在 Webpack 橫空出世後,將原本 JavaScript 模組化的概念利用 loader 擴充到 CSS、圖片等資源,並藉由其彈性化的設定與 plugin 來決定我們如何開發、打包,讓前端工程化這件事得以實現。因此當時許多前端框架的生態系也對齊採用 Webpack,像是早期的 create-react-appVue CLI,甚至到當前的 Next.js 穩定版仍是使用 Webpack。

但 Webpack 發展了十多年到現在,一直為人所詬病的不外乎幾點:

  • 設定複雜不易懂
  • 在大型專案中的開發體驗較差
    • dev server 啟動時間慢
    • 開發過程中的 HMR 速度慢
  • 在大型專案中的 production build 時間變久

以下將針對這三個問題做展開,來聊聊現代網頁開發中,有哪些工具試圖解決這些問題。

Build tool vs Bundler vs Compiler

先做個名詞定義,關於從網頁開發到打包部署過程中,你可能會看到 build tool、bundler、compiler 這些詞,我一開始也很難分清楚前兩者的不同。

Build tool 中文有人翻作構建工具,但我覺得還是蠻困惑的,因為其中有 build 這個字,是不是就代表跟 build code 有關?那跟 bundle 又有何不同?

直到我看到 Rsbuild 文件中的這張圖:

build tool vs bundler

看起來 build tool 比較多指的是開發時用到的 dev server 這個功能,另外也跟 HMR (Hot Module Replacement) 這個特性比較有關。但在看了許多文件對自己的定義後,我覺得其實這些詞不同工具間也是有點混用,所以不用太糾結。

就像 Webpack 文件上稱自己為 bundler,但其實他後來也內建整合了 webpack-dev-server 這個 build tool 的功能;Rspack 又更亂了,雖然他有將其中的 build tool 部份稱為 Rsbuild 區分開來,但 Rsbuild 的文件中又提到它的特性不只有 dev server 的功能,然後跟其他工具的效能比較圖根本就是 Rspack/Rsbuild 都是同一張。

rspack vs rsbuild performance
rspack vs rsbuild performance

簡單整理的話,我覺得可以說是該工具代表性的品牌名 (Webpack、Vite、Rspack) 可以統稱為打包與開發工具,其中在各自生態系的整合中能做到 dev serverbundler 的功能,然後在開發或打包時會用上底層需要的 compiler (像是 Babel、SWC) 去做語法轉譯,細分的話可能會是這樣:

  • Webpack:本體是 bundler,其中整合 webpack-dev-server 做 build tool
  • Vite:本體是 build tool,其中分別在 dev 與 production 中整合 esbuildRollup 做 bundler
  • Rspack:本體是 bundler,若需要 build tool 的功能可用 Rsbuild
  • 以前的 CRA/Vue CLI:本體是有對 webpack-dev-server 做客製化版的 build tool,打包時則是用 Webpack 當作 bundler

另外其實我覺得這邊名詞定義不用太糾結的還有 compiler 與 transpiler。像是 Babel 與 SWC (Speedy Web Compiler) 都稱自己為 compiler。

但就 CS 定義上來說:

  • Compile 指的是將 source code 編譯成機器能讀懂的 machine code 等低階語言
  • Transpile 指的是將 source code 轉譯成另一種 source code,像是將 ES6 轉成 ES5、TypeScript 轉成 JavaScript

但可能也是因為名詞定義這種事有時候本來就參雜了一些主觀想法,所以不用太糾結。(ref)

問題一:解決難學難用的問題

針對第一點,分別有幾個工具嘗試簡化 Webpack 設定複雜的問題,但因為算是比較早期的工具,這邊不會細講,只簡單做一些簡介。

Rollup (2015)

  • 主要用來做為 ESM 的模組打包工具,設定上相對 Webpack 簡單許多
  • Vite 背後採用的 bundler

Parcel (2018)

  • 號稱 zero configuration 的打包工具
  • NPM trends 上看相比其他 bundler 下載數較少
  • 有趣的是好奇看了它的原始碼發現其中有 Rust,於是找到了它的 roadmap,看起來其中一個目標有打算重寫為 Rust 來改善打包效率。
npm trends

問題二:解決開發體驗不佳的問題

在 Webpack、Rollup、Parcel 這些工具中的 dev server 用的是 bundle-based 的模式,也就是每次你在開發儲存修改後,要在畫面上看到改變就一定需要經過一個完整的打包過程。

直到 ESM 的發展與普及後,開發者想到可以利用瀏覽器支援原生 ESM 的這個特性來提升 dev server 的開發體驗,因此有了 Native-ESM-based 的架構,從先驅 Snowpack 到現在廣為人知的 Vite。

關於上面的這個運作原理我還蠻有興趣深入理解的,但怕這邊寫太多會在後面章節中另外展開,這邊先做個簡介

Snowpack (2019)

算是 Vite 的啟迪者 (ref)。2022 年官方宣布不再維護的消息,建議可以改用 Vite 作為替代方案,而之後原開發團隊跑去開發 Astro,而 Astro 的 CLI 也是建立於 Vite 之上。

冷知識:Snowpack 的作者 Fred K. Schott 後來有寫了一篇關於他經營 Snowpack 開源專案的心得,以及如何將這些經驗帶到 Astro 的心路歷程 —— 《5 Things I Learned Building Snowpack to 20,000 Stars》

Vite (2020)

Vue 作者 Evan You 所開發,原本是想改善 Vue CLI 開發體驗不佳的問題,另外可能也是他做 Vue 開源做得有點累的 side project,現也成為 Solid、Qwik、Astro、Svelte 等現代前端框架的 dev server 基礎。其他內容後面講解 Vite 的運作原理時會再細談。

問題三:解決打包速度過慢的問題

最後第三個在正式版打包速度過慢的問題,近代出現許多後起之秀,一改以往 JavaScript-based 的 bundler 的做法,改用效能更好的靜態語言,像是 Go-based 的 esbuild,還有此系列中會更有興趣關注的 Rust-based bundler,也因此這個系列才會命名為「Rust 的戰國時代」,後面會著重在這些工具的介紹,這邊先做個簡介。

esbuild (2020)

  • 作者為 Figma 的共同創辦人兼曾經的 CTO Evan Wallace 用 Go 開發的 bundler
  • 號稱比 Webpack 快一百倍
  • 若環境允許的狀況下,可以在 Webpack 專案中使用 esbuild-loader 取代 babel-loader、ts-loader 來提升轉譯速度

Turbopack (2022)

  • Vercel 在 Next.js Conf 2022 上發佈,由 Webpack 作者 Tobias Koppers 領銜開發,但目前尚不穩定
  • 社群普遍認為未來可能成為 Next.js 的專武,其他生態系可能會靠向 Vite 或 Rspack (ref)
  • 曾與 Vite 作者 Evan You 對於效能問題有過一番論戰 (ref)
nextjs conf 2022 - turbopack demo

Rspack (2023)

  • 主要由 ByteDance Web Infra 團隊開發,他們的技術部落格有許多不錯的資源,有興趣可以深入閱讀
  • 2024.08 正式釋出 v1.0.0 (ref)
  • 最大的特色是 Webpack 兼容,使得 legacy 大型專案能漸進式改善效能問題

Rolldown (2024)

  • 在 2023.10 的 ViteConf 2023 上,由 Evan You 釋出將由 Vite 與 Rollup 團隊共同開發,邁向 Rust 之路
  • 2024.03 開源,目前正在開發中
rolldown

另外還有幾套最近才知道但沒研究很深的 build tool,這裡也記錄一下:

小結

今天稍微說明了下 build tool 與 bundler 的區別,並從 Webpack 的三個問題,帶出各款現代效能飛快的 build tool、bundler 的簡介,避免篇幅過長,細節會再後面繼續開展。明天也將會繼續聊聊 Vite 生態系的大小事。