跳至內容

為何選擇 Vite

問題所在

在瀏覽器支援 ES 模組之前,開發者沒有原生的機制以模組化的方式撰寫 JavaScript。這就是為什麼我們都熟悉「打包」的概念:使用工具來爬取、處理並將我們的原始模組串連成可以在瀏覽器中執行的檔案。

隨著時間的推移,我們看到了像 webpackRollupParcel 這樣的工具,這些工具極大地改善了前端開發者的開發體驗。

然而,隨著我們建構越來越多的複雜應用程式,我們處理的 JavaScript 數量也在急劇增加。大型專案包含數千個模組並不罕見。我們開始遇到基於 JavaScript 工具的效能瓶頸:啟動開發伺服器通常需要不合理的長時間等待(有時甚至長達數分鐘!),即使使用熱模組替換(HMR),檔案編輯也需要幾秒鐘才能反映在瀏覽器中。緩慢的回饋循環會嚴重影響開發人員的生產力和滿意度。

Vite 旨在透過利用生態系統中的新進展來解決這些問題:瀏覽器中原生 ES 模組的可用性,以及用編譯為原生語言編寫的 JavaScript 工具的興起。

伺服器啟動緩慢

在冷啟動開發伺服器時,基於打包器的建置設定必須急切地爬取並建置您的整個應用程式,然後才能提供服務。

Vite 透過首先將應用程式中的模組分為兩類來改善開發伺服器的啟動時間:依賴項原始碼

  • 依賴項大多是純 JavaScript,在開發期間不會經常變更。一些大型依賴項(例如,具有數百個模組的元件庫)處理起來也相當耗費資源。依賴項也可能以各種模組格式(例如,ESM 或 CommonJS)發佈。

    Vite 使用 esbuild 預先綁定依賴項。esbuild 是用 Go 編寫的,並且預先綁定依賴項的速度比基於 JavaScript 的打包器快 10-100 倍。

  • 原始碼通常包含需要轉換的非純 JavaScript(例如,JSX、CSS 或 Vue/Svelte 元件),並且會經常編輯。此外,並非所有原始碼都需要同時載入(例如,使用基於路由的程式碼分割)。

    Vite 透過 原生 ESM 提供原始碼服務。這本質上是讓瀏覽器接管打包器的一部分工作:Vite 只需要在瀏覽器請求時按需轉換和提供原始碼。條件動態導入背後的程式碼僅在目前畫面實際使用時才會被處理。

Bundle based dev server entry ··· route route module module module module ··· Bundle Server ready
Native ESM based dev server entry ··· route route module module module module ··· Server ready Dynamic import (code split point) HTTP request

更新緩慢

當在基於打包器的建置設定中編輯檔案時,重新建置整個套件是無效的,原因很明顯:更新速度會隨著應用程式的大小呈線性下降。

在某些打包器中,開發伺服器在記憶體中執行打包,以便在檔案變更時只需要使模組圖的一部分失效,但它仍然需要重新建構整個套件並重新載入網頁。重新建構套件可能會很耗費資源,而重新載入網頁會清除應用程式的目前狀態。這就是為什麼某些打包器支援熱模組替換(HMR):允許模組「熱替換」自身,而不影響頁面的其餘部分。這極大地改善了 DX - 然而,在實踐中,我們發現即使是 HMR 更新速度也會隨著應用程式大小的增加而顯著惡化。

在 Vite 中,HMR 是透過原生 ESM 執行的。當編輯檔案時,Vite 只需要精確地使編輯的模組及其最接近的 HMR 邊界之間的鏈失效(大多數情況下只有模組本身),使得 HMR 更新始終快速,而與您的應用程式大小無關。

Vite 還利用 HTTP 標頭來加速整個頁面的重新載入(再次,讓瀏覽器為我們做更多的工作):原始碼模組請求透過 304 Not Modified 進行條件式請求,而依賴項模組請求則透過 Cache-Control: max-age=31536000,immutable 強烈快取,因此一旦快取,它們就不會再次連線到伺服器。

一旦您體驗過 Vite 的速度,我們高度懷疑您是否願意再次忍受打包開發。

為何在生產環境中打包

儘管現在已廣泛支援原生 ESM,但由於巢狀導入造成的額外網路往返,在生產環境中發佈未打包的 ESM 仍然效率低下(即使使用 HTTP/2)。為了在生產環境中獲得最佳的載入效能,最好還是使用 tree-shaking、lazy-loading 和常見區塊分割(為了更好的快取)來打包您的程式碼。

確保開發伺服器和生產建置之間的最佳輸出和行為一致性並不容易。這就是為什麼 Vite 附帶了預先配置的 建置命令,其中內建了許多 效能最佳化

為何不使用 esbuild 打包?

儘管 Vite 利用 esbuild 來在開發中預先綁定一些依賴項,但 Vite 不使用 esbuild 作為生產建置的打包器。

Vite 目前的外掛 API 與使用 esbuild 作為打包器不相容。儘管 esbuild 更快,但 Vite 對 Rollup 靈活的外掛 API 和基礎架構的採用極大地促進了其在生態系統中的成功。目前,我們認為 Rollup 提供了更好的效能與彈性之間的權衡。

Rollup 也一直在努力改進效能,在其 v4 中將其解析器切換為 SWC。並且正在努力建構 Rollup 的 Rust 移植版本,名為 Rolldown。一旦 Rolldown 準備就緒,它可以取代 Vite 中的 Rollup 和 esbuild,顯著提高建置效能並消除開發和建置之間的不一致性。您可以觀看 Evan You 在 ViteConf 2023 的主題演講以瞭解更多詳細資訊

Vite 與 X 有何不同?

您可以查看 比較 部分,以瞭解有關 Vite 與其他類似工具的不同之處的更多詳細資訊。

在 MIT 許可下發布。(ccee3d7c)