Pack
文件
核心概念

核心概念

讓我們深入了解 Turbopack 的內部結構,找出它如此快速的原因。

Turbo 引擎

Turbopack 如此快速,是因為它建構在 Rust 的可重複使用函式庫上,此函式庫支援稱為 Turbo 引擎的增量運算。以下是它的運作方式

函式層級快取

在由 Turbo 引擎驅動的程式中,您可以將某些函式標記為「要記住」。當呼叫這些函式時,Turbo 引擎將記住呼叫它們時所使用的參數,以及它們傳回的內容。然後,它會將這些資訊儲存在記憶體快取中。

以下是此功能在套件管理工具中可能呈現的簡化範例

我們從對兩個檔案 api.tssdk.ts 呼叫 readFile 開始。然後,我們 bundle 這些檔案,將它們 concat 在一起,最後得到 fullBundle。所有這些函式呼叫的結果都會儲存在快取中以供後續使用。

假設我們在開發伺服器上執行。您在電腦上儲存 sdk.ts 檔案。Turbopack 會收到檔案系統事件,並知道它需要重新運算 readFile("sdk.ts")

由於 sdk.ts 的結果已變更,我們需要再次 打包 它,然後需要再次串接。

最重要的是,api.ts 沒有變更。我們從快取中讀取其結果,並將其傳遞給 串接。因此,我們不必再次讀取和重新打包它,從而節省時間。

現在,想像一下在一個真正的打包器中,有數千個檔案需要讀取和轉換要執行。心智模式是一樣的。透過記住函式呼叫的結果,並避免重複之前已完成的工作,你可以節省大量的時間。

快取

Turbo 引擎目前將其快取儲存在記憶體中。這表示快取將持續到執行它的程序為止,這對於開發伺服器來說很有效。當你在 Next.js 13+ 中執行 next dev --turbo 時,你將使用 Turbo 引擎啟動快取。當你取消開發伺服器時,快取將被清除。

未來,我們計畫保留這個快取,儲存在檔案系統中或 Turborepo 等遠端快取中。這表示 Turbopack 可以記住跨執行和機器完成的工作。

它如何提供協助?

這種方法讓 Turbopack 能夠極快速地計算應用程式的增量更新。這最佳化了 Turbopack 在開發中處理更新的方式,表示你的開發伺服器將始終對變更做出快速回應。

未來,永久快取將開啟更快速的生產建置。透過記住跨執行完成的工作,新的生產建置只能重新建置變更的檔案,這可能會大幅節省時間。

依據要求編譯

Turbo 引擎有助於在你的開發伺服器上提供極快的更新,但還有另一個重要的指標需要考量,那就是啟動時間。你的開發伺服器啟動執行的速度越快,你就能越快開始工作。

有兩種方法可以讓流程更快,一是工作更快,二是減少工作量。對於啟動開發伺服器,減少工作量的方法是編譯僅啟動所需的程式碼

頁面級別編譯

2-3 年前的 Next.js 版本在顯示開發伺服器之前,會編譯整個應用程式。在 Next.js 11(在新分頁中開啟) 中,我們開始編譯僅你要求的頁面上的程式碼

這樣比較好,但還不完美。當你導覽到 /users 時,我們會將所有用戶端和伺服器模組、動態匯入的模組,以及引用的 CSS 和圖片打包。這表示,如果你的頁面有很大一部分被隱藏,或隱藏在分頁後面,我們還是會將其編譯。

請求級別編譯

Turbopack 足夠聰明,可以編譯僅你要求的程式碼。這表示,如果瀏覽器要求 HTML,我們只編譯 HTML,而不是 HTML 參考的任何內容。

如果瀏覽器想要一些 CSS,我們只會編譯它,而不編譯引用的圖片。在 next/dynamic 後面有一個大型圖表程式庫嗎?在顯示圖表的標籤顯示之前,不會編譯它。Turbopack 甚至知道除非你的 Chrome DevTools 開啟,否則不編譯原始碼對應表

如果我們使用原生 ESM,我們會得到類似的行為。除了原生 ESM 會產生大量對伺服器的請求,如我們在 為什麼使用 Turbopack 區段中所討論的。透過請求級別編譯,我們可以減少請求數量使用原生速度來編譯它們。正如你在我們的 基準測試 中所看到的,這提供了顯著的效能提升。