為什麼選擇 Turbopack?
當我們著手創建 Turbopack 時,我們想要解決一個問題。我們一直在努力改進 Next.js 的速度。我們從幾個基於 JS 的工具遷移開來。Babel,淘汰。Terser,淘汰。我們的下一個目標是另一個基於 JS 的工具,webpack。
取而代之成為我們的目標。但要用什麼取代呢?
新一代原生速度的打包工具正在興起,但在評估市場上的打包工具後,我們決定建立自己的工具。為什麼?
統一圖
像 Next.js 這樣的框架之所以如此受歡迎,很大一部分原因是,使用目前這一代的打包工具實作諸如 SSR(現在是 RSC)之類的功能並非易事。您需要為每個輸出環境(瀏覽器、伺服器等)建立多個編譯器,並管理它們之間的通訊,以便它們的套件最終正確地組合在一起。
我們想從 Next.js 和任何選擇使用 Turbopack 的框架中消除這種維護負擔。我們還可以通過設計一個單一的統一圖來創建更清晰、更穩定的實現,該圖可用於為多個環境生成套件。
打包 vs 原生 ESM
像 Vite 這樣的框架使用一種技術,在開發模式下不打包應用程式原始碼。相反,它們依賴瀏覽器的原生 ES 模組系統。這種方法帶來了極其快速的更新,因為它們只需要轉換單個檔案。
我們嘗試了這種方法,但在由許多模組組成的大型應用程式中遇到了擴展問題。瀏覽器中大量的串聯網路請求導致啟動時間相對較慢。對於瀏覽器而言,如果它能以盡可能少的網路請求接收到它需要的程式碼,則速度會更快,即使是在本機伺服器上也是如此。
這就是為什麼我們決定,像 webpack 一樣,我們希望 Turbopack 在開發伺服器中打包程式碼。Turbopack 可以更快地完成此操作,尤其是對於較大的應用程式,因為它使用 Rust 編寫,並跳過了僅在生產環境中才需要的最佳化工作。
增量計算
有兩種方法可以加快處理速度:減少工作量或並行執行工作。我們知道,如果我們想要製作最快的打包工具,我們需要同時盡力使用這兩種方法。
我們決定建立一個可重複使用的 Turbo 建置引擎,類似於 Parcel 的請求管理器和 rustc 的查詢系統,用於分散式和增量行為。Turbo 引擎的工作方式類似於函數呼叫的排程器,允許在所有可用的核心上並行化函數呼叫。
Turbo 引擎還會快取其排程的所有函數的結果,這意味著它永遠不需要重複執行相同的工作。簡單來說,它以最快的速度執行最少的工作。
延遲打包
早期版本的 Next.js 嘗試在開發模式下打包整個網路應用程式。我們很快意識到這種「急切」的方法並非最佳。現代版本的 Next.js 僅打包開發伺服器請求的頁面。例如,如果您前往 localhost:3000
,它只會打包 pages/index.jsx
及其導入的模組。
這種更「延遲」的方法(僅在絕對必要時才打包資源)是快速開發伺服器的關鍵。原生 ESM 在沒有太多魔法的情況下處理此問題 - 您請求一個模組,該模組請求其他模組。但是,由於上述原因,我們想建立一個打包工具。
esbuild 沒有「延遲」打包的概念 - 除非您專門針對某些進入點,否則它都是全部或全無。
Turbopack 的開發模式會根據收到的請求建立應用程式的導入和匯出最小圖形,並僅打包必要的最小程式碼。在增量計算文件中瞭解更多資訊。
摘要
我們希望
- 支援統一圖。這允許框架使用可以針對多個環境的單一編譯器。
- 建立一個打包工具。在處理大型應用程式時,打包工具的效能優於原生 ESM。
- 使用增量計算。Turbo 引擎將其帶入 Turbopack 架構的核心 - 最大化速度並最大限度地減少完成的工作量。
- 最佳化我們的開發伺服器的啟動時間。為此,我們建立了一個延遲資源圖,僅計算請求的資源。
這就是我們選擇建立 Turbopack 的原因。