前言
Bundle or Bundleless?自 2015 年 ESM 標準發佈後,路線之爭就開始逐步升温。轉眼間,時間已來到 2021 年。如果白酒的車你錯過了,那麼不妨看看 Bundleless,或許它就是前端圈的下一位「茅台」。
前端構建當下的問題
不得不説,曾經把自己定位為「打包器」的 Webpack,如今已形成強大的構建生態,儼然一統江湖。但前端構建的道路還遠沒有走到最後。隨着業務的發展,前端工程的複雜度越來越高,構建方面的也開始暴露出新的問題。
構建時間逐步拉長
相信許多前端同學剛入行時,都經歷過「刷新一下全都有」的幸福時光:寫幾個 HTML 標籤,寫幾句內嵌代碼,瀏覽器中就會呈現出美妙的 UI。而如今,業務工程越來越複雜,代碼量連年增長,構建的時間也越來越長。曾經「秒級構建」的前端,終究躋身「分鐘級構建」的圈子了。

前端工程構建時間的拉長,自然使得前端開發者在日常業務工作中的狀態,從圖左逐漸運動到了圖右。

模塊標準引領方向
如果我們縱觀前端領域的發展,就可以看到標準是如何推動各大瀏覽器建設,整個前端生態又是如何發生的變化。
2002 年,AJAX 推出,此後前端承擔的工作越來越多。彼時,瀏覽器廠各行其是,因此兼容性是當時的主要問題。於是 2006 年,jQuery 的出現進一步帶動了前端的發展。
2009 - 2011 年,CommonJS、AMD、UMD 相繼為 JS 帶來了模塊規範。同一時期,部分遵循 CommonJS 的 Node 為 JS 帶來了運行環境,為前端工程化的解鎖奠定基礎:
- 模塊加載工具開始涌現,如 RequireJS、SeaJS 等
- 包管理工具,如 npm、spm 等
- 輕量的打包器開始出現,如 Browserify
- 任務工具開始出現,如 Gulp
Angular、React、Vue 等的相繼火爆,也推動了前端的又一波浪潮:它們的發展提高了前端在業務中的表達能力,並向更高程度的工程化提出訴求。
2015 年,HTTP/2.0 推出,同時 JS 迎來了自己的模塊標準 ESM:ES2015 一發布,Babel 就讓開發者們用上了 ES Module,真香。於是此後的幾年,Webpack & Babel 幾乎成了前端工程化的代名詞,甚至讓人以為,前端工程化已成定局。
2018 年,Chrome、Safari、Firefox 相繼完成了對 ESM 的支持。但得益於 Webpack 生態對 CommonJS、AMD、UMD 的支持,開發者們對 ESM 的享用更多是在編碼階段和一定程度的 Tree-shaking,在構建層面並沒有直接的得利。
總結
當下時間點,出現了新的契機:
其一,「工程體積的日益增長」與「亟待提升的構建性能」之間的矛盾;
其二,「先進的前端模塊標準」與「落後的前端模塊規範」之間的矛盾。
Bundleless 為什麼是答案
Bundleless 説到底,就是指無打包構建,與我們當下流行的打包構建相對,而打包器則是我們前端開發者用於將 JS 模塊打包成單一的、可在瀏覽器內運行的文件的工具。
為什麼過去需要打包
這一問題在社區也有非常多的總結,概況來講,主要包括以下理由:
- HTTP/1.1 各瀏覽器有並行連接限制
- 瀏覽器不支持模塊系統(如 CommonJS 包不能直接在瀏覽器運行)
- 代碼依賴關係與順序管理
HTTP/1.1 各瀏覽器默認並行連接數
| 瀏覽器 | Firefox 3+ | Opera 12 | Safari 5 | IE 7 | IE 10 | Edge | Chrome |
|---|---|---|---|---|---|---|---|
| 並行連接 | 6 | 6 | 6 | 2 | 8 | 6 | 6 |
為什麼開始嘗試不打包
近幾年時間,標準的確立、瀏覽器大廠和前端生態的跟進,使得「不打包」成為可能:
- HTTP/2.0 多路並用
- 各大瀏覽器逐一支持 ESM
- 越來越多的 npm 包擁抱 ESM(儘管很多包的依賴並不是)
我們可以發現:
- 通過打包來減少網絡請求數量從而提高性能的優化手段理論上在 HTTP/2.0 下會變得不再必要;
-
ESM 標準的推廣和各大瀏覽器的支持:
- 讓模塊代碼可以直接在瀏覽器中運行
- 原生的解決了代碼依賴和複用的問題
- 會進一步推動越來越多的 npm 包支持 ESM,甚至會出現新的包管理或分發方式
Bundleless vs Bundle
模塊加載的對比
如果是打包式構建,在模塊加載時,實際上加載的是若干模塊的集合。這種方式的優點是以少量的請求連接數完成 JS 腳本的下載。如果是無打包式構建,模塊的加載則是基於原生模塊方案,直接獲取具體的模塊腳本。
本地開發構建的對比
如果是打包式構建,無論是項目啓動還是文件變更,都需要完整的走一遍打包過程。以 Webpack 為例,我們就會經歷依賴分析、代碼轉譯和打包的過程,哪怕我們只是簡單的修改了一行文案。當然,Split chunk 會在一定程度上緩解這一問題,但粒度仍然偏大。
而無打包式構建,在啓動過程中基本只是啓動服務(當然不同的 Bundleless 方案可能還會做些其他的工作),而不用對業務代碼進行依賴分析、打包,ESM 會幫助我們在瀏覽器中完成依賴的分析。當文件發生變更時,本地開發服務只是提供了文件的映射,只需要重新轉譯對應的文件,並重新替換即可。
結論
以上,我們可以知道:
- 打包過程的必要性已降低
- 擁抱 ESM 是未來趨勢
社區在領域內的工作
概覽
前端構建並不只是構建工具的問題。事實上,「構建」和「分發」共同組成了前端工程的構建,只不過通常情況下,我們是通過 npm install 將三方包下載下來,並打包到構建結果中實現的。
構建可以分為兩種類型。
一種是基於服務的構建方式,通常服務於實際生產。我們可以再細分成本地服務構建和遠端服務構建。本地服務構建就是我們常規的操作,目前基本已經被 Webpack 統治,是 Bundle 方案的代表;Snowpack、Vite、Web Dev Server 則是目前非常火的 Bundleless 方案,近一年的時間裏勢頭迅猛。遠端服務構建則是依託雲能力的玩法,把構建過程放在服務端完成,從而把本地的開發流程搬到 Web 上,並給出於本地服務構建基本一致的體驗。
另一種是基於瀏覽器的構建方式,通常面向 Demo 的快速搭建或預覽方案。Codesandbox、StackBlitz、CodePen 和 Riddle 是業內較出色的方案,整體是在瀏覽器端實現代碼的編譯、打包、構建和運行。當然,具體到各個方案的細節,通常對服務還是有一定依賴。
目前來看,100% 在瀏覽器端進行打包、構建,現階段並不是最理想的方案。隨着 Bundleless 的發展,瀏覽器 Bundleless 和包分發平台的結合會得到進一步的發展,並逐步影響前端工程的架構。
🗻Snowpack
原理
這一部分在 Snowpack 的文檔上有一定的講解。整體來説,Snowpack 儘可能利用了現有前端生態的工具,對三方包打包來壓縮依賴鏈,對業務代碼走無構建路線,以此提供 Bundleless 體系下的開發體驗。值得一提的是,Snowpack 的構建速度很快,這得益於內置打包工具 esbuild 的發展。

Snowpack vs Webpack
我們不妨將其與 Webpack 進行一個對比。
啓動時間,如上文所説,Webpack 會完整打包整個項目,因此隨着項目體積的增長,啓動時間也會越發漫長;而 Snowpack 主要是啓動本地的服務,對於 Snowpack 來説,儘管初次啓動時會分析三方依賴,並通過 Rollup 將其進行打包,但是打包結果會緩存在 node_modules/.cache/snowpack/development 目錄下,後續就可以享受到飛一樣的啓動。
構建時間,對於 Webpack 而言,構建時長會隨着項目體積整體以線性方式增長;而 Snowpack 的模式則是 O(1) 的複雜度(當然這裏也有點小噱頭)。
緩存能力,可以説 Webpack 的緩存利用率尚有優化空間。儘管我們可以通過 Split Chunk,合理的劃分打包方式,但如果我們只是改了一句文案,那麼用户側仍然會重新獲取對應 Chunk 資源。Snowpack 的緩存利用率近乎完美。業務代碼文件發生變更,直接替代產出資源,其他全部可返回緩存;三方依賴包,如 react.js,則直接更新該包,其他全部可用緩存。不過,儘管生產環境優化可以做 Tree-shaking,但是業務代碼本身,Snowpack 並不會做處理(只是以 ESM 來對待),即使使用 Snowpack 生態的 Webpack 插件來做生產環境的構建也是如此,所以是近乎完美,這是相對於理想的 DCE(dead code elimination) 而言的。Webpack 在生產環境會把沒有使用到的代碼 Tree-shaking 掉,不可謂不強大。
至於調試體驗,因為 Webpack 需要打包,因此在調試的時候我們依賴 SourceMap 來幫助我們看到源碼。但對於 Snowpack 而言(實際上 Bundleless 模式都是如此),我們並不強依賴於 SourceMap,如果轉譯後的代碼閲讀無礙(ES6 其實還好嘛),就可以直接進行單文件調試。
不過即使 Snowpack 有千番好,整個 Bundleless 生態還不足以取代 Webpack。Webpack 終究是一代神器,只是我們明白 Bundleless 也確實代表了未來。
⚡️Vite
Vite 是尤大的力作,本篇便不再對其進行討論。有趣的是,他和 Webpack 作者 Sean 在推上的討論可以看出,大佬們也在 Bundleless 方向不斷髮力,Webpack 成為了大家發起挑戰的目標。

總結
本文以 Bundleless 為切入點,結合前端構建的發展過程,對當下無構建方案進行了討論。未來我們會更多的在此方面進行實踐。
文章可隨意轉載,但請保留此原文鏈接。
非常歡迎有激情的你加入 ES2049 Studio,簡歷請發送至 caijun.hcj@alibaba-inc.com 。