在瀏覽器支持ES模塊之前,JavaScript并沒有提供的原生機制讓開發(fā)者以模塊化的方式進行開發(fā)。這也正是我們對“打包”這個概念熟悉的原因:使用工具抓取、處理并將我們的源碼模塊串聯(lián)成可以在瀏覽器中運行的文件。
時過境遷,我們見證了諸如 webpack、Rollup 和 Parcel 等工具的變遷,它們極大地改善了前端開發(fā)者的開發(fā)體驗。
然而,當我們開始構(gòu)建越來越大型的應(yīng)用時,需要處理的 JavaScript 代碼量也呈指數(shù)級增長。包含數(shù)千個模塊的大型項目相當普遍。我們開始遇到性能瓶頸 —— 使用 JavaScript 開發(fā)的工具通常需要很長時間(甚至是幾分鐘?。┎拍軉娱_發(fā)服務(wù)器,即使使用 HMR,文件修改后的效果也需要幾秒鐘才能在瀏覽器中反映出來。如此循環(huán)往復(fù),遲鈍的反饋會極大地影響開發(fā)者的開發(fā)效率和幸福感。
Vite 旨在利用生態(tài)系統(tǒng)中的新進展解決上述問題:瀏覽器開始原生支持 ES 模塊,且越來越多 JavaScript 工具使用編譯型語言編寫。
當冷啟動開發(fā)服務(wù)器時,基于打包器的方式啟動必須優(yōu)先抓取并構(gòu)建你的整個應(yīng)用,然后才能提供服務(wù)。
Vite通過在一開始將應(yīng)用中的模塊區(qū)分為依賴和源碼兩類,改進了開發(fā)服務(wù)器啟動時間。
基于打包器啟動時,重建整個包的效率很低。原因顯而易見:因為這樣更新速度會隨著應(yīng)用體積增長而直線下降。
一些打包器的開發(fā)服務(wù)器將構(gòu)建內(nèi)容存入內(nèi)存,這樣它們只需要在文件更改時使模塊圖的一部分失活,但它也仍需要整個重新構(gòu)建并重載頁面。這樣代價很高,并且重新加載頁面會消除應(yīng)用的當前狀態(tài),所以打包器支持了動態(tài)模塊熱重載(HMR):允許一個模塊 “熱替換” 它自己,而不會影響頁面其余部分。這大大改進了開發(fā)體驗 —— 然而,在實踐中我們發(fā)現(xiàn),即使采用了 HMR 模式,其熱更新速度也會隨著應(yīng)用規(guī)模的增長而顯著下降。
在 Vite 中,HMR 是在原生 ESM 上執(zhí)行的。當編輯一個文件時,Vite 只需要精確地使已編輯的模塊與其最近的 HMR 邊界之間的鏈失活(大多數(shù)時候只是模塊本身),使得無論應(yīng)用大小如何,HMR 始終能保持快速更新。
Vite 同時利用 HTTP 頭來加速整個頁面的重新加載(再次讓瀏覽器為我們做更多事情):源碼模塊的請求會根據(jù) ?304 Not Modified
? 進行協(xié)商緩存,而依賴模塊請求則會通過 ?Cache-Control: max-age=31536000,immutable
? 進行強緩存,因此一旦被緩存它們將不需要再次請求。
一旦你體驗到 Vite 的神速,你是否愿意再忍受像曾經(jīng)那樣使用打包器開發(fā)就要打上一個大大的問號了。
盡管原生 ESM 現(xiàn)在得到了廣泛支持,但由于嵌套導(dǎo)入會導(dǎo)致額外的網(wǎng)絡(luò)往返,在生產(chǎn)環(huán)境中發(fā)布未打包的 ESM 仍然效率低下(即使使用 HTTP/2)。為了在生產(chǎn)環(huán)境中獲得最佳的加載性能,最好還是將代碼進行 tree-shaking、懶加載和 chunk 分割(以獲得更好的緩存)。
要確保開發(fā)服務(wù)器和生產(chǎn)環(huán)境構(gòu)建之間的最優(yōu)輸出和行為一致并不容易。所以 Vite 附帶了一套構(gòu)建優(yōu)化的構(gòu)建命令,開箱即用。
雖然?esbuild
?快得驚人,并且已經(jīng)是一個在構(gòu)建庫方面比較出色的工具,但一些針對構(gòu)建 應(yīng)用 的重要功能仍然還在持續(xù)開發(fā)中 —— 特別是代碼分割和 CSS 處理方面。就目前來說,Rollup 在應(yīng)用打包方面更加成熟和靈活。盡管如此,當未來這些功能穩(wěn)定后,我們也不排除使用?esbuild
?作為生產(chǎn)構(gòu)建器的可能。
更多建議: