儲存庫
文件
核心概念
任務相依性

任務相依性

當您表達任務之間的關聯性時,Turborepo 最為強大。我們將這些關係稱為「依賴關係」,但它們與您從 package.json 檔案安裝的套件依賴關係不同。雖然 Turborepo 確實了解您的工作區,但它不會自動繪製它們的任務之間的任何關係,除非您在 turbo.json 中透過 dependsOn 設定表達它們。

讓我們逐步了解一些常見模式,說明如何讓任務依賴於其他任務。

來自同一個工作區

可能有些任務需要在其他任務之前執行。例如,build 可能需要在 deploy 之前執行。

如果兩個任務都在同一個工作區中,您可以這樣指定關係

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
  "pipeline": {
    "build": {},
    "deploy": {
      // A workspace's `deploy` task depends on the `build` task of the same workspace.
      "dependsOn": ["build"]
    }
  }
}

這表示每當執行 turbo deploy 時,build 也會在同一個工作區中執行。

來自依賴的工作區

單一儲存庫中的常見模式是宣告工作區的 build 任務應僅在它所依賴的所有工作區build 任務完成後執行。

這可能會令人困惑,因為它同時指的是工作區依賴關係和任務依賴關係,而這兩個概念不同。工作區依賴關係是 dependenciesdevDependenciespackage.json 中,而任務依賴關係是 dependsOn 鍵在 turbo.json 中。

符號 ^(稱為「插入符號」)明確宣告任務取決於工作區中它所依賴的任務。

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
  "pipeline": {
    "build": {
      // A workspace's `build` command depends on its dependencies'
      // and devDependencies' `build` commands being completed first
      "dependsOn": ["^build"],
    }
  }
}

使用上述設定,如果應用程式從另一個工作區安裝套件,套件的 build 指令碼將永遠在應用程式的 build 指令碼之前執行。

來自任意工作區

有時,您可能希望工作區任務取決於另一個工作區任務。這對於從 lernarush 遷移的儲存庫特別有幫助,其中任務預設會在不同的階段執行。有時,這些設定會做出無法在上述簡單的 pipeline 設定中表達的假設。或者,您可能只是想在 CI/CD 中使用 turbo 時,表達應用程式或微服務之間的任務順序。

在這些情況下,您可以使用 <workspace>#<task> 語法在 pipeline 設定中表達這些關係。以下範例說明取決於 backenddeployhealth-check 指令碼,以及 ui 工作區的 test 指令碼的 frontend 應用程式的 deploy 指令碼:

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
  "pipeline": {
    // Explicit workspace-task to workspace-task dependency
    "frontend#deploy": {
      "dependsOn": ["ui#test", "backend#deploy", "backend#health-check"]
    }
  }
}

針對 frontend#deploy 的這個明確設定,可能看起來與 testdeploy 任務設定有衝突,但並非如此。由於 testdeploy 沒有依賴於其他工作區(例如 ^<task>),因此它們可以在其工作區的 buildtest 腳本完成後隨時執行。

備註

  1. 儘管這個 <workspace>#<task> 語法是一個有用的逃生艙口,但我們通常建議將其用於部署編排任務,例如健康檢查,而不是建置時間依賴項,以便 Turborepo 能更有效率地最佳化這些任務
  2. 工作區任務不會繼承快取設定。您必須重新宣告 outputs
  3. <workspace> 必須與工作區的 name 鍵相符,否則任務將會被忽略。

沒有依賴關係

空的依賴關係清單(dependsOn 未定義或為 [])表示在這個任務之前不需要執行任何動作!畢竟,它沒有依賴關係。

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
  "pipeline": {
    // A workspace's `lint` command has no dependencies and can be run any time.
    "lint": {}
  }
}

任務外部的依賴關係

假設您有一個共用的 ui 套件,您在兩個應用程式 docsweb 中使用它。

apps/
  docs/package.json # Depends on ui
  web/package.json  # Depends on ui
packages/
  ui/package.json   # No workspace dependencies
turbo.json
package.json

您在工作區中撰寫了一些 TypeScript,現在是時候執行 tsc 來檢查您的類型。這裡有兩個需求:

  • 所有類型檢查並行執行,以保持速度:因為類型檢查的結果彼此無關,所以您可以並行執行所有檢查。
  • 依賴關係中的變更應導致快取遺漏:如果 ui 套件變更,docsweb 中的類型檢查任務應知道遺漏快取。

為達成此目的,您將在圖形中建立一個假的遞迴任務並依賴它。

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
   "pipeline": {
     "topo": {
       "dependsOn": ["^topo"]
     },
     "typecheck": {
       "dependsOn": ["topo"]
     }
   }
 }

由於 topo 任務在您的腳本中不存在,Turborepo 將「立即」完成任務,然後查看依賴於該工作區的任何工作區。因此,您的任務將並行執行,同時仍了解它們與任務圖形中其他工作區的關係。

這裡的 topo 名稱並非特殊名稱。它是「拓撲」的簡稱,有助於說明其存在的目的,但您可以將此任務命名為任何您想要的內容。

為什麼這麼做有效?

我們可以透過檢視幾乎符合我們需求的管線,更深入了解為什麼這麼做有效。

您可以透過從任務定義中省略 dependsOn 來達成任務的平行處理,如下所示

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
    "pipeline": {
      "typecheck": {} // Uh oh, not quite!
    }
}

您的 typecheck 任務將會成功平行執行 - 但它們不會知道其工作區的相依性!

我們可以使用以下步驟來示範

  1. 執行 turbo typecheck
  2. 變更 ui 套件中的一些原始碼
  3. 執行 turbo typecheck --filter=web

如果您執行此操作,您將會在步驟 3 命中快取 - 但您不應該這麼做!您可能在 web 工作區中建立一個類型錯誤,而這個錯誤來自於 ui 套件程式碼中的變更。步驟 3 中的快取命中將會是不正確的,並會向您隱藏類型錯誤。

若要解決此問題,您可以選擇直接依賴您的拓撲相依圖,就像您對 build 任務所做的一樣

{
  "$schema": "https://turbo.dev.org.tw/schema.json",
  "pipeline": {
    "typecheck": {
      "dependsOn": ["^typecheck"] // Uh oh, not quite!
    }
  }
}

現在您擁有正確的快取行為:當 ui 程式碼變更時,web 將會錯失快取。這很棒 - 但我們剛剛失去了讓我們的管線執行得如此快速的平行處理。在 ui 工作區中的 typecheck 任務現在必須在 web 中的任務開始之前結束

如果我們可以依賴於在 ui 中「立即完成」的任務,以便在依賴的工作空間中盡快啟動 typecheck 指令,那會如何?

這正是「假的」topo 任務發揮作用的地方

{
   "$schema": "https://turbo.dev.org.tw/schema.json",
   "pipeline": {
     "topo": {
       "dependsOn": ["^topo"]
     },
     "typecheck": {
       "dependsOn": ["topo"]
     }
   }
 }

在此管線中,我們宣告一個稱為 topo 的「合成」任務。由於我們在任何 package.json 檔案中都沒有 topo 指令碼,turbo typecheck 管線將直接執行所有 typecheck 指令碼,以符合我們的首要需求。

但這個 topo 任務也建立了一個「合成」工作空間任務相依性,從 webui,以及從 docsui。這表示當你在 ui 中變更程式碼時,你也會在 webdocs 中的工作空間取得快取遺漏,符合第二個需求。

管線宣告 typecheck 相依於 topo 任務,而 topo 相依於 ^topo。以英文來說,這表示 相同 工作空間的 topo 任務必須在所有 typecheck 任務之前執行,而所有 套件相依性topo 任務必須在 topo 任務本身之前執行。

你可能會問,為什麼 typecheck 沒有直接相依於 ^topo?因為我們希望我們的 Workspace 能透過合成任務以 遞迴 方式連接套件相依性。如果