最近對前端構建工具的一些理解
作者:0o 華仔 o0
https://juejin.cn/post/7121279495494959111
前言
最近有幸在前端團隊裏面做了一次關於 webpack 的技術分享。在分享的準備過程中,爲了能讓大家更好的理解 webpack,特意對市面上以前和現在流行的構建工具做了一個梳理總結。在整理和分享的過程中,獲益匪淺,對前端構建工具有了新的認識。在這裏,將自己的一些思考總結寫出來,希望也能給到對構建工具同樣感興趣的同學一點幫助。
本文的目錄結構如下:
-
構建工具的前世今生 [1]
-
js 模塊化的發展史和構建工具的變化 [2]
-
結束語 [3]
構建工具的前世今生
談到構建工具,大家首先想到的肯定就是 Webpack
以及現在最🔥的 Vite
。Webpack
,功能強大,生態豐富,從面世到今天,一直是很受大家歡迎;Vite
採用 unbundle
構建模式,帶來了極致的開發體驗,給開發人員以新的選擇。
在這兩個構建工具之外,還有其他的構建工具,如和 Webpack
、Vite
類似的 Rollup
、Parcel
、Esbuild
,自動化構建工具 grunt
、gulp
,以及更加久遠的 YUI Tool
。
這些工具的存在,構成了前端構建工具的發展史。
YUI Tool + Ant
YUI tool
是 07 年左右出現的一個構建工具,功能比較簡單,用於壓縮混淆 css
和 js
代碼,需要配合 java
的 Ant
使用。
當時 web 應用開發主要採用 JSP
,還不像現在這樣前後端分離,通常是由 java 開發人員來編寫 js、css 代碼,前端代碼都是和後端 java 代碼放在一起的。因此前端代碼的壓縮混淆也就基於 java 實現了。
Grunt / Gulp
Grunt
/ Gulp
都是運行在 node
環境上的自動化工具。
在開發過程中,我們可以將一些常見操作如解析 html
、es6 代碼轉換爲 es5
、less / sass 代碼轉換爲 css 代碼
、代碼檢查
、代碼壓縮
、代碼混淆
配置成一系列任務,然後通過 Grunt
/ Gulp
自動執行這些任務。
Grunt
和 Gulp
的不同點:
-
使用
Grunt
的過程中,會產生一些中間態的臨時文件。一些任務生成臨時文件,其它任務可能會基於臨時文件再做處理並生成最終的構建後文件,導致出現多次I/O
。 -
Gulp
有文件流的概念,通過管道將多個任務和操作連接起來,不會產生臨時文件,減少了I/O
操作,流程更清晰,更純粹,大大加快了構建的速度。
Webpack / Rollup / Parcel
Webpack
、Rollup
、Parcel
統稱爲靜態模塊打包器
。
這一類構建工具,通常需要指定入口 - entry
,然後以 entry
爲起點,通過分析整個項目內各個源文件之間的依賴關係,構建一個模塊依賴圖 - module graph
,然後再將 module graph
分離爲三種類型的 bundle
: entry
所在的 initial bundle
、lazy load
需要的 async bundle
和自定義分離規則的 custome bundle
。
這幾個構建工具各有優勢:
-
Webpack
大而全,配置靈活,生態豐富,是構建工具的首選。 -
Parcel
號稱零配置,使用簡單,適合不太需要定製化構建的項目使用。 -
Rollup
推崇ESM
標準開發,打包出來的代碼乾淨,適用於組件庫開發。
Vite / Esbuild
新一代構建工具。
esbuild
, 基於 go
語言實現,代碼直接編譯成機器碼 (不用像 js 那樣先解析爲字節碼,再編譯爲機器碼),構建速度比 webpack
更快。
vite
, 開發模式下藉助瀏覽器對 ESM
的支持,採用 nobundle
的方式進行構建,能提供極致的開發體驗;生產模式下則基於 rollup
進行構建。
js 模塊化的發展史和構建工具的變化
javascript
語言設計之初,只是作爲一個簡單的腳本語言用來豐富網站的功能,並不像 java
、c++
那樣有 module
的概念,發展到現在的模樣,也經歷了相當長的時間。
這段時間,可以簡單歸納爲:
-
青銅時代
- no module; -
白銀時代
- cjs、amd、cmd、umd、esm 相繼出現; -
黃金時代
- 組件模塊化;
不同的時代,構建工具也不同。
青銅時代
由於沒有 module
的概念, javascript
無法在語言層面實現模塊之間的相互隔離
、相互依賴
,只能由開發人員手動處理。
相應的,早期的 web
開發也比較簡單甚至簡陋:
-
通過
對象
、iife(或者閉包)
的方式實現模塊隔離
; -
通過手動確定
script
的加載順序
確定模塊之間的依賴關係
。 -
jsp
開發模式,沒有專門的前端,html
、js
、css
代碼通常也由後端開發人員編寫。
爲了節省帶寬
和保密
,通常需要對前端代碼做壓縮混淆
處理。這個時候,構建工具爲 YUI Tool
+ Ant
。
白銀時代
chrome v8
引擎 和 node
的橫空出世,給前端帶來了無限的可能。
同時,javascript
的模塊化標準也有了新的發展:
-
commonjs
規範,適用於node
環境開發。 -
amd
、cmd
規範,適用於瀏覽器
環境。 -
umd
,兼容amd
、commonjs
,代碼可以同時運行在瀏覽器
和node
環境。 -
ESM
,即ES6 module
(這個時候還不是很成熟);
同時還出現了 less
、sass
、 es6
、 jslint
、 eslint
、typescript
等新的東西, 前端角色也開始承擔越來越重要的作用,慢慢的獨立出來。
有了 node
提供的平臺,大量的工具開始湧現:
-
requirejs
提供的r.js
插件,可以分析 amd 模塊依賴關係
、合併壓縮 js
、優化 css
; -
less
/sass
插件,可以將less
/sass
代碼轉化爲css
代碼; -
babel
,可以將es6
轉化爲es5
; -
typescript
,將ts
編譯爲js
; -
jslint
/eslint
,代碼檢查; -
...
這個時候,我們可以將上面的的這些操作配置成一個個任務,然後通過 Grunt
/ Gulp
自動執行任務。
黃金時代
基於 Angular
、Vue
、React
三大框架和 Webpack
的使用,組件模塊化
成爲前端開發的主流模式。同時 ESM
規範也原來越成熟,被更多的瀏覽器支持。
以 React
和 Webpack
爲例,通常我們會將一個應用涉及到的所有的功能拆分爲一個個組件,如路由組件、頁面組件、表單組件、表格組件等,一個組件對應一個源文件,然後通過 Webpack
將這些源文件打包。在開發過程中,還會通過 Webpack
開啓一個 local server
,實時查看代碼的運行效果。
Webpack
是一個靜態模塊打包器,它會以 entry
指定的入口文件爲起點,分析整個項目內各個源文件之間的依賴關係,構建一個模塊依賴圖 - module graph
,然後將 module graph
分離爲多個 bundle
。在構建 module graph
的過程中,會使用 loader
處理源文件,將它們轉化爲瀏覽器可以是識別的 js
、css
、image
、音視頻
等。
隨着時間的發展, Webpack
的功能越來越來強大,也迎來諸多對手。
Webpack1
|
|
Rollup 出現(推崇 ESM 規範,可以實現 tree shaking, 打包出來的代碼更乾淨)
|
|
Webpack2(也實現了 tree shaking, 但是配置還是太繁瑣了)
|
|
Parcel (號稱 0 配置)
|
|
Webpack4(通過 mode 確定 development 和 production 模式,各個模式有自己的默認配置)
|
|
Webpack5(持久化緩存、module federation)
Esbuild(採用 go 語言開發,比 Webpack 更快)
Vite(推崇 ESM 規範,開發模式採用 nobundle,更好的開發體驗)
複製代碼
豐富的構建工具,形成了百花綻放的局面,可用於不同的情形,給開發人員帶來了越來越多的選擇。
結束語
目前來看,構建工具在整個前端體系中佔據的位置是越來越重要。只會 Webpack 甚至不懂構建工具已經無法滿足日常開發。這就需要我們時時學習,緊跟時代的腳步,瞭解最新的技術,不斷前進。
儘管前路坎坷, 依然相信未來可期,加油 💪🏻 !
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/15YxshMsZ7FJyLUfXZHqCQ