Rush Stack商店部落格活動
跳至主要內容

增量建置

Rush 的增量建置功能會跳過已是最新的專案,藉此加速建置程序。在此情境中,「已是最新的」表示

  1. 專案已在本機建置,且
  2. 自上次建置以來,其輸入檔案和 NPM 相依性未變更,且
  3. 如果專案相依於任何其他 Rush 專案,則這些專案也必須是最新的,且
  4. 命令列參數未變更。(例如,在執行 rush build 後叫用 rush build --production 會需要重新建置。)

根據預設,「輸入檔案」是指專案資料夾下的所有來源檔案,除了 .gitignore 排除的檔案;您可以使用 rush-project.json 設定檔自訂詳細資料。

此功能可以與專案選取參數結合使用,讓使用者明確告知 Rush 要處理哪些專案。增量建置會重複使用本機磁碟上現有的輸出。這與 Rush 的建置快取功能形成對比,後者可以從雲端儲存容器提取先前建置的輸出。

如何使用

若要查看增量建置的實際運作情況,只需執行 rush build 命令兩次

rush install

# This might take several minutes...
rush build

# ...but the second time it finishes in just a few seconds.
rush build

原生的 rush build 已預設為增量建置。(而 rush rebuild 是此命令的非增量變體。)如果您定義自己的自訂批次命令,您也可以透過在command-line.json 設定檔中啟用 "incremental" 選項,將其設定為增量建置。

其運作方式為何?

您的專案建置指令碼(由 rushx buildnpm run build 叫用)可能已經實作其自己的增量最佳化。例如,Heft 會維護各種工作的多個快取。但是,即使 rushx build 對於專案沒有執行任何工作,仍需要非零的額外負擔,才能產生 Node.js 程序、評估 JavaScript 檔案,以及比較個別檔案的時間戳記。假設所有這些作業對於一個專案僅需要 500 毫秒。如果您的單一儲存庫有 100 個專案,則在所有項目皆為最新的情況下,這會產生 100 x 0.5 = 50 秒的計算時間。

Rush 會透過單次傳遞執行儲存庫的自身全域分析來消除此額外負擔,如此一來,對於最新的專案完全不會叫用建置指令碼。作為額外的最佳化,Rush 的增量分析會仰賴檔案雜湊而不是時間戳記。例如,如果您切換到不同的 Git 分支,然後再切換回來,許多檔案的時間戳記可能會遭到變更,但是只要來源檔案內容未變更,Rush 的增量分析就不會受到影響。檔案雜湊是由 @rushstack/package-deps-hash 程式庫管理。雜湊會儲存在類似 <您的專案>/.rush/temp/package-deps_<工作名稱>.json 的檔案中。檢查此檔案可以深入瞭解演算法的運作方式。

增量分析實際上包含三種不同的行為

  • 不進行增量最佳化: 如果叫用的 Rush 命令不是增量的(在 command-line.json 中為 incremental: false),則每次都會重新執行作業。

  • 輸出保留: 如果停用建置快取(在 build-cache.json 中為 "buildCacheEnabled": false),則 Rush 會檢查自上次在同一部本機電腦上建置以來,輸入檔案是否已變更。如果沒有修改任何檔案,則 Rush 會假設專案資料夾下的輸出檔案是最新的,並且會「跳過」專案而不執行任何工作。請注意,透過手動竄改輸出檔案,很容易違反此假設。

  • 快取還原: 如果啟用建置快取(在 build-cache.json 中為 "buildCacheEnabled": true),則 Rush 會改為查詢快取提供者,以查看此專案是否已事先建置。快取提供者可能是雲端儲存或本機磁碟快取。對於快取命中,會刪除專案的輸出檔案,並以從快取還原的檔案取代。

未來可能的改進: 在目前的實作中,啟用建置快取時,永遠不會使用輸出保留策略。換句話說,專案輸出資料夾一律會先清除,然後從快取還原檔案取代,這在磁碟上的檔案已是最新的情況下,似乎沒有效率。合併輸出保留快取還原方法是否會更有效率?

工程上的挑戰在於,當啟用建置快取時,我們也需要寫入快取,這需要對輸出的正確性抱持高度的信心。輸出保留演算法目前不會驗證輸出檔案的雜湊或檢查是否有額外的或遺失的檔案。如果實作這類驗證,其執行時間必須快於 tarball 擷取,而 tarball 擷取已經是非常快速的作業。

僅建置已變更的專案(不安全)

假設我們的單一儲存庫有下列專案

a sample monorepo

在上述圖例中,圓圈代表本機專案,而非外部 NPM 相依性。從 DC 的箭頭表示 D 相依於 C;這表示必須先建置 C,才能建置 D

假設在重新建置所有項目後,我們對專案 B 下的來源檔案進行變更。專案 CD 相依於 B,因此它們也需要建置

rush build --impacted-by B

我們可以叫用

# This command will rebuild B, C, and D
rush build

但是,如果您知道您對 C 所做的變更不會影響其 API 合約呢?例如,您可能更新了按鈕控制項的色彩,或錯誤訊息中的一些文字。

--changed-projects-only 旗標會告知 Rush 僅建置已變更檔案的專案

rush build --only B

我們會像這樣叫用它

# This command will rebuild B (but ignore the effects for C and D)
rush build --changed-projects-only

--changed-projects-only 是「不安全」的,因為如果下游專案實際上需要重新建置,則可能會發生錯誤。此參數會假設您比 Rush 更了解哪些項目真正需要建置,藉此節省時間。如果該假設不正確,您可以隨時執行 rush build 來回到良好的狀態。

另請參閱