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

啟用分階段建置

預設情況下,Rush 會在每個專案資料夾中分別執行建置指令碼 (類似於 npm run build) 來建置每個專案,並在相依性圖允許的情況下平行處理專案。從 Rush 的角度來看,在該建置指令碼中發生的所有事情都是單一操作。

分階段建置」是一種透過將個別操作定義為可在專案上執行的「階段」來提高平行性的方法。例如,如果專案 B 相依於專案 A,我們可以先建置專案 A,然後在平行執行專案 A 的單元測試時開始建置專案 B。

注意:分階段建置建立於建置快取功能的基礎之上,並且需要該功能。如果您尚未為您的單一儲存庫啟用建置快取,請參閱啟用建置快取

啟用實驗功能

common/config/rush/experiments.json 中,啟用 "phasedCommands" 實驗功能。

{
"phasedCommands": true
}

定義階段

common/config/rush/command-line.json 中,新增一個 "phases" 區段,如下所示

{
"phases": [
{
/**
* The name of the phase. Note that this value must start with the \"_phase:\" prefix.
*/
"name": "_phase:build",

/**
* The dependencies of this phase.
*/
"dependencies": {
"upstream": ["_phase:build"]
},

/**
* Normally Rush requires that each project's package.json has a \"scripts\" entry matching the phase name. To disable this check, set \"ignoreMissingScript\" to true.
*/
"ignoreMissingScript": true,

/**
* By default, Rush returns a nonzero exit code if errors or warnings occur during a command. If this option is set to \"true\", Rush will return a zero exit code if warnings occur during the execution of this phase.
*/
"allowWarningsOnSuccess": false
},
{
"name": "_phase:test",
"dependencies": {
"self": ["_phase:build"]
},
"ignoreMissingScript": true,
"allowWarningsOnSuccess": false
}
]
}

在此範例中,我們定義了兩個階段 -- _phase:build_phase:test_phase:build 操作相依於其上游專案的 _phase:build 操作 (使用傳統的 Rush 相依性圖)。_phase:test 操作不相依於任何上游專案,但需要先完成其「自身」專案的 _phase:build 操作。請注意,階段名稱必須以 _phase: 開頭。

個別專案可以選擇不實作階段 (如果已啟用 ignoreMissingScript),但它們無法定義自己的階段,或變更階段的相依性。這可確保階段在您的單一儲存庫內行為一致,無論您正在建置哪個專案子集。

重新定義建置和測試指令

common/config/rush/command-line.json"commands" 區段中,將 "build" 指令重新定義為 phased 指令,而不是 bulk 指令,並指定您希望它執行的階段。在以下範例中,我們也定義了 "test" 指令。

{
"commands": [
{
"commandKind": "phased",
"name": "build",
"phases": ["_phase:build"],
"enableParallelism": true,
"incremental": true
},

// No need to define "rebuild", by default, it is the same as build
// but with incremental=false.

{
"commandKind": "phased",
"name": "test",
"summary": "Build and test all projects.",
"phases": ["_phase:build", "_phase:test"],
"enableParallelism": true,
"incremental": true
},

{
"commandKind": "phased",
"name": "retest",
"summary": "Build and test all projects.",
"phases": ["_phase:build", "_phase:test"],
"enableParallelism": true,
"incremental": false
}
]
}

此指令定義展示了分階段建置的另一個實用功能:我們可以建立我們的「階段」建置區塊,然後從這些區塊建立指令。我們可以定義 rush build 的意思為「建置所有專案而不執行測試」,而 rush test 的意思為「建置所有專案並執行測試」,而不是讓 rush build 為所有專案執行建置和測試。

將參數指派給階段

如果您已在 command-line.json 中為建置指令定義任何自訂參數,您現在需要將它們關聯到階段,以便 Rush 知道哪些階段可以接受您的參數。

以下是一些範例

{
"parameters": [
{
"longName": "--production",
"parameterKind": "flag",
"description": "Perform a production build, including minification and localization steps",
"associatedCommands": ["build", "rebuild", "test", "retest"],
"associatedPhases": ["_phase:build"]
},
{
"longName": "--update-snapshots",
"parameterKind": "flag",
"description": "Update unit test snapshots for all projects",
"associatedCommands": ["test", "retest"],
"associatedPhases": ["_phase:test"]
}
]
}

在這裡,我們定義了一個可在建置指令的所有 4 種變體上指定的旗標 (--production),但它只會傳遞到「建置」階段。而且,我們定義了另一個只能在 testretest 指令上指定的旗標 (--update-snapshots),並且只會傳遞到 test 階段。

因此,如果我們要執行此指令

rush test --production --update-snapshots

Rush 會將 --production 參數傳遞到每個專案的 _phase:build 指令碼,然後將 --update-snapshots 參數傳遞到每個專案的 _phase:test 指令碼。

將階段指令碼新增至您的專案

在您單一儲存庫中每個專案的 package.json 檔案中,新增新的 _phase: 指令碼

{
"scripts": {
"_phase:build": "heft build --clean",
"_phase:test": "heft test --no-build",
"build": "heft build --clean",
"test": "heft test --clean"
}
}

上面的範例嘗試調整開發人員對 buildtest 指令的預期

  • 移至專案資料夾並執行 rushx build 會清除並建置專案,而不執行測試。
  • 移至專案資料夾並執行 rushx test 會清除、建置和測試專案。
  • 執行 rush build --only <project> 會清除並建置專案,而不執行測試。
  • 執行 rush test --only <project> 會清除、建置和測試專案。

在可能的情況下,對於您定義的任何自訂階段,請記住此模式 -- 重要的不是階段的實作方式與 rushx 指令完全相同,而是 rush <something>rushx <something> 會產生相似的結果 (如果適用)。

某些專案可能沒有任何有意義的階段工作要做,在這種情況下,您可以將其定義為空操作 (""),或將其完全省略 (如果在階段定義中指定了 ignoreMissingScript)。

定義每個階段的輸出資料夾名稱

在每個專案 (或最好是每個裝配設定檔) 的 rush-project.json 設定檔中,重新定義您的 operationSettings,以便每個資料夾僅在一個階段中指定。例如

{
"operationSettings": [
// Old configuration (before phases)
{
"operationName": "build",
"outputFolderNames": ["lib", "lib-commonjs", "dist", "temp"]
},
// New configuration (after phases)
{
"operationName": "_phase:build",
"outputFolderNames": ["lib", "lib-commonjs", "dist"]
},
{
"operationName": "_phase:test",
"outputFolderNames": ["temp/coverage", "temp/jest-reports"]
}
]
}

請注意 _phase:build_phase:test 指定的輸出資料夾之間沒有重疊 -- 這是分階段建置的一個重要的新要求。一般而言,如果某個操作的輸出可以被不同的操作修改,Rush 就無法可靠地快取該操作的輸出,因此您應該將操作結構化,以便如果 _phase:build 產生一個 "lib" 資料夾,則沒有其他操作會將輸出放入該資料夾。

分階段建置功能仍在開發中。歡迎提供意見!

一些相關的 GitHub 問題供您追蹤