聊聊前端構(gòu)建這十年
大廠技術(shù)??高級前端??Node進階
點擊上方?程序員成長指北,關(guān)注公眾號
回復1,加入高級Node交流群

◆??寫在前面
前端模塊化/構(gòu)建工具從最開始的基于瀏覽器運行時加載的?RequireJs/Sea.js?到將所有資源組裝依賴打包?webpack/rollup/parcel的bundle類模塊化構(gòu)建工具,再到現(xiàn)在的bundleless基于瀏覽器原生 ES 模塊的?snowpack/vite,前端的模塊化/構(gòu)建工具發(fā)展到現(xiàn)在已經(jīng)快 10 年了。
本文主要回顧 10 年間,前端模塊化/構(gòu)建工具的發(fā)展歷程及其實現(xiàn)原理。
看完本文你可以學到以下知識:
模塊化規(guī)范方案
前端構(gòu)建工具演變,對前端構(gòu)建有一個系統(tǒng)性認識
各個工具誕生歷程及所解決的問題
webpack/parcel/vite 的構(gòu)建流程及原理分析
(因涉及一些歷史、趨勢,本文觀點僅代表個人主觀看法)
◆??基于瀏覽器的模塊化
· CommonJS
一切的開始要從CommonJS規(guī)范說起。
CommonJS?本來叫ServerJs,其目標本來是為瀏覽器之外的javascript代碼制定規(guī)范,在那時NodeJs還沒有出生,有一些零散的應用于服務端的JavaScript代碼,但是沒有完整的生態(tài)。
之后就是?NodeJs?從?CommonJS?社區(qū)的規(guī)范中吸取經(jīng)驗創(chuàng)建了本身的模塊系統(tǒng)。
· RequireJs 和 AMD
CommonJs?是一套同步模塊導入規(guī)范,但是在瀏覽器上還沒法實現(xiàn)同步加載,這一套規(guī)范在瀏覽器上明顯行不通,所以基于瀏覽器的異步模塊?AMD(Asynchronous Module Definition)規(guī)范誕生。
define(id?, dependencies?, factory);

AMD規(guī)范采用依賴前置,先把需要用到的依賴提前寫在?dependencies?數(shù)組里,在所有依賴下載完成后再調(diào)用factory回調(diào),通過傳參來獲取模塊,同時也支持require("beta")的方式來獲取模塊,但實際上這個require只是語法糖,模塊并非在require的時候?qū)耄歉懊嬲f的一樣在調(diào)用factory回調(diào)之前就被執(zhí)行,關(guān)于依賴前置和執(zhí)行時機這點在當時有很大的爭議,被?CommonJs社區(qū)所不容。
在當時瀏覽器上應用CommonJs還有另外一個流派?module/2.0, 其中有BravoJS的 Modules/2.0-draft 規(guī)范和?FlyScript的 Modules/Wrappings規(guī)范。
代碼實現(xiàn)大致如下:

奈何RequireJs如日中天,根本爭不過。
關(guān)于這段的內(nèi)容可以看玉伯的?前端模塊化開發(fā)那點歷史。
· Sea.js 和 CMD
在不斷給?RequireJs?提建議,但不斷不被采納后,玉伯結(jié)合RequireJs和module/2.0規(guī)范寫出了基于 CMD(Common Module Definition)規(guī)范的Sea.js。
define(factory);

在 CMD 規(guī)范中,一個模塊就是一個文件。模塊只有在被require才會被執(zhí)行。
相比于 AMD 規(guī)范,CMD 更加簡潔,而且也更加易于兼容?CommonJS?和?Node.js?的?Modules?規(guī)范。
· 總結(jié)
RequireJs和Sea.js都是利用動態(tài)創(chuàng)建script來異步加載 js 模塊的。
在作者還是前端小白使用這兩個庫的時候就很好奇它是怎么在函數(shù)調(diào)用之前就獲取到其中的依賴的,后來看了源碼后恍然大悟,沒想到就是簡單的函數(shù)?toString?方法

通過對factory回調(diào)toString拿到函數(shù)的代碼字符串,然后通過正則匹配獲取require函數(shù)里面的字符串依賴
這也是為什么二者都不允許require更換名稱或者變量賦值,也不允許依賴字符串使用變量,只能使用字符串字面量的原因
規(guī)范之爭在當時還是相當混亂的,先有CommonJs社區(qū),然后有了 AMD/CMD 規(guī)范和?NodeJs?的?module?規(guī)范,但是當那些CommonJs的實現(xiàn)庫逐漸沒落,并隨著NodeJs越來越火,我們口中所說的CommonJs?好像就只有?NodeJs所代表的modules了。
◆??bundle 類的構(gòu)建工具
· Grunt
隨著NodeJs的逐漸流行,基于NodeJs的自動化構(gòu)建工具Grunt誕生
Grunt可以幫我們自動化處理需要反復重復的任務,例如壓縮(minification)、編譯、單元測試、linting 等,還有強大的插件生態(tài)。
Grunt采用配置化的思想:

基于?nodejs?的一系列自動化工具的出現(xiàn),也標志著前端進入了新的時代。
· browserify
browserify致力于在瀏覽器端使用CommonJs,他使用跟?NodeJs?一樣的模塊化語法,然后將所有依賴文件編譯到一個bundle文件,在瀏覽器通過
