Turborepo

設定任務

Turborepo 總是會按照您的 turbo.json 設定檔套件圖中描述的順序執行任務,並在可能的情況下平行處理工作,以確保一切盡可能快速執行。這比一次執行一個任務更快,也是 Turborepo 如此快速的原因之一。

例如,yarn workspaces run lint && yarn workspaces run test && yarn workspaces run build 看起來會像這樣

A graphical representation of `turbo run lint test build`. It shows all tasks running in parallel, with much less empty space where scripts are not being ran.

但是,若要使用 Turborepo **更快**地完成相同的工作,您可以使用 turbo run lint test build

A graphical representation of `turbo run lint test build`. It shows all tasks running in parallel, with much less empty space where scripts are not being ran.

開始使用

根目錄的 turbo.json 檔案是您註冊 Turborepo 將執行的任務的地方。一旦您定義了任務,您就可以使用 turbo run 執行一個或多個任務。

  • 如果您是從頭開始,我們建議使用 create-turbo 建立新的儲存庫並編輯 turbo.json 檔案,以嘗試本指南中的程式碼片段。
  • 如果您要在現有的儲存庫中採用 Turborepo,請在儲存庫的根目錄中建立 turbo.json 檔案。您將使用它來了解本指南中其餘的設定選項。
turbo.json
package.json

定義任務

tasks 物件中的每個索引鍵都是可以使用 turbo run 執行的任務。Turborepo 將會在您的套件中搜尋其 package.json 中**與任務名稱相同的指令碼**。

若要定義任務,請使用 turbo.json 中的 tasks 物件。例如,一個名為 build 的基本任務,沒有相依性和沒有輸出,可能看起來像這樣

./turbo.json
{
  "tasks": {
    "build": {} // Incorrect!
  }
}

如果您在此時執行 turbo run build,Turborepo 將會平行執行您套件中的所有 build 指令碼,而且不會快取任何檔案輸出。**這將很快導致錯誤。** 您缺少一些重要的部分才能讓它按照您預期的方式運作。

按照正確順序執行任務

dependsOn 索引鍵用於指定必須先完成的任務,然後才能開始執行另一個任務。例如,在大多數情況下,您希望在應用程式的 build 指令碼執行之前完成函式庫的 build 指令碼。若要執行此操作,您可以使用下列 turbo.json

./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"] 
    }
  }
}

您現在擁有您預期的建置順序,先建置相依性,再建置相依者

但請小心。 在此時,您尚未標記建置輸出以進行快取。若要執行此操作,請跳到指定輸出章節。

使用 ^ 相依於相依性中的任務

^ 微語法會告知 Turborepo 從相依性圖的底部開始執行任務。如果您的應用程式相依於名為 ui 的函式庫,且該函式庫具有 build 任務,則會**先**執行 ui 中的 build 指令碼。一旦成功完成,您的應用程式中的 build 任務就會執行。

這是一個重要的模式,因為它可以確保您應用程式的 build 任務具有其編譯所需的所有必要相依性。此概念也適用於您的相依性圖成長為具有多個層級任務相依性的更複雜結構。

相依於相同套件中的任務

有時,您可能需要確保相同套件中的兩個任務以特定順序執行。例如,您可能需要在執行相同函式庫中的 test 任務之前,先在函式庫中執行 build 任務。若要執行此操作,請將 dependsOn 索引鍵中的指令碼指定為純字串(沒有 ^)。

./turbo.json
{
  "tasks": {
    "test": {
      "dependsOn": ["build"] 
    }
  }
}

相依於特定套件中的特定任務

您也可以指定要相依的特定套件中的個別任務。在下面的範例中,utils 中的 build 任務必須在執行任何 lint 任務之前執行。

./turbo.json
{
  "tasks": {
    "lint": {
      "dependsOn": ["utils#build"] 
    }
  }
}

您也可以更明確地指定相依的任務,將其限制為特定套件

./turbo.json
{
  "tasks": {
    "web#lint": {
      "dependsOn": ["utils#build"] 
    }
  }
}

使用此設定,您 web 套件中的 lint 任務只能在 utils 套件中的 build 任務完成後才能執行。

無相依性

有些任務可能沒有任何相依性。例如,用於在 Markdown 檔案中尋找錯別字的任務可能不需要關心您其他任務的狀態。在這種情況下,您可以省略 dependsOn 索引鍵或提供一個空陣列。

./turbo.json
{
  "tasks": {
    "spell-check": {
      "dependsOn": [] 
    }
  }
}

指定 outputs

Turborepo 會快取您任務的輸出,讓您永遠不會重複執行相同的工作。我們將在快取指南中深入討論這個問題,但我們先確保您的任務已正確設定。

outputs 索引鍵會告知 Turborepo 在任務成功完成時應快取的**檔案和目錄**。**如果沒有定義此索引鍵,Turborepo 將不會快取任何檔案。後續執行時命中快取將不會還原任何檔案輸出。**

以下是一些常用工具的輸出範例

./turbo.json
{
  "tasks": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**"] 
    }
  }
}

Glob 是相對於套件的,因此 dist/** 將會處理每個套件分別輸出的 dist。如需更多關於為 outputs 索引鍵建立 glob 模式的資訊,請參閱globbing 規格

指定 inputs

inputs 索引鍵用於指定您要包含在任務雜湊中的檔案,以進行快取。依預設,Turborepo 將包含套件中 Git 追蹤的所有檔案。但是,您可以使用 inputs 索引鍵更明確地指定要包含在雜湊中的檔案。

例如,用於在 Markdown 檔案中尋找錯別字的任務可以定義如下

./turbo.json
{
  "tasks": {
    "spell-check": {
      "inputs": ["**/*.md", "**/*.mdx"] 
    }
  }
}

現在,**只有** Markdown 檔案中的變更才會導致 spell-check 任務遺漏快取。

此功能會選擇退出 Turborepo 的所有預設 inputs 行為,包括追蹤來源控制所追蹤的變更。這表示您的 .gitignore 檔案將不再被採用,您需要確保您不會使用 glob 捕捉這些檔案。

若要還原預設行為,請使用 $TURBO_DEFAULT$ 微語法

使用 $TURBO_DEFAULT$ 還原預設值

預設的 inputs 行為通常是您任務所需要的。但是,您可以透過微調 inputs,忽略已知不會影響任務輸出的檔案變更,來提高某些任務的快取命中率。

因此,您可以使用 $TURBO_DEFAULT$ 微語法來微調預設的 inputs 行為。

./turbo.json
{
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", "!README.md"] 
    }
  }
}

在這個任務定義中,Turborepo 將對 build 任務使用預設的 inputs 行為,但會忽略對 README.md 檔案的變更。如果 README.md 檔案發生變更,任務仍會命中快取。

註冊根任務

您也可以使用 turbo 在 Workspace 根目錄的 package.json 中執行腳本。例如,除了每個套件中的 lint 任務之外,您可能還想為 Workspace 根目錄中的檔案執行 lint:root 任務。

./turbo.json
{
  "tasks": {
    "lint": {
      "dependsOn": ["^lint"]
    },
    "//#lint:root": {} 
  }
}

現在根任務已註冊,turbo run lint:root 將會執行該任務。您也可以執行 turbo run lint lint:root 來執行所有 linting 任務。

何時使用根任務

  • Workspace 根目錄的 Linting 和格式化:您的 Workspace 根目錄中可能有一些您想要 lint 和格式化的程式碼。例如,您可能想在根目錄中執行 ESLint 或 Prettier。
  • 增量移轉:在您移轉到 Turborepo 時,您可能會有一些尚未移至套件的腳本。在這種情況下,您可以建立一個根任務,開始移轉,然後再將任務分散到各個套件。
  • 沒有套件範圍的腳本:您可能有一些腳本在特定套件的上下文中沒有意義。這些腳本可以註冊為根任務,以便您仍然可以使用 turbo 來執行它們,以實現快取、平行化和工作流程的目的。

進階使用案例

使用套件組態

套件組態是直接放置在套件中的 turbo.json 檔案。這允許套件為其自己的任務定義特定的行為,而不影響儲存庫的其餘部分。

在擁有許多團隊的大型 monorepo 中,這讓團隊可以更好地控制自己的任務。若要瞭解更多資訊,請造訪套件組態文件

執行副作用

某些任務無論如何都應該執行,例如快取建置後的部署腳本。對於這些任務,請將 "cache": false 新增至您的任務定義。

./turbo.json
{
  "tasks": {
    "deploy": {
      "dependsOn": ["^build"],
      "cache": false
    },
    "build": {
      "outputs": ["dist/**"]
    }
  }
}

可以平行執行的相依任務

儘管某些任務依賴於其他套件,它們仍然可以平行執行。符合此描述的任務範例是 linters,因為 linter 不需要等待相依性中的輸出才能成功執行。

因此,您可能會想要像這樣定義您的 check-types 任務

./turbo.json
{
  "tasks": {
    "check-types": {} // Incorrect!
  }
}

這會平行執行您的任務,但不會考慮相依性中的原始碼變更。這表示您可以

  1. 對您的 ui 套件的介面進行重大變更。
  2. 執行 turbo check-types,命中依賴於 ui 的應用程式套件的快取。

這是錯誤的,因為應用程式套件將顯示成功的快取命中,儘管它尚未更新為使用新介面。在您的編輯器中手動檢查應用程式套件中的 TypeScript 錯誤可能會顯示錯誤。

因此,您對您的 check-types 任務定義進行了小的變更

./turbo.json
{
  "tasks": {
    "check-types": {
      "dependsOn": ["^check-types"] // This works...but could be faster!
    }
  }
}

如果您再次測試在您的 ui 套件中進行重大變更,您會注意到快取行為現在是正確的。但是,任務不再平行執行。

為了滿足這兩個要求(正確性和平行性),您可以將轉換節點引入您的任務圖表。

./turbo.json
{
  "tasks": {
    "transit": {
      "dependsOn": ["^transit"]
    },
    "check-types": {
      "dependsOn": ["transit"]
    }
  }
}

這些轉換節點使用一個不執行任何操作的任務來建立套件相依性之間的關係,因為它與任何 package.json 中的腳本都不相符。因此,您的任務可以平行執行並且感知其內部相依性的變更。

在這個範例中,我們使用了名稱 transit,但您可以將任務命名為 Workspace 中尚未存在的任何腳本名稱。

後續步驟

設定 turbo.json 文件中還有更多選項可供您在接下來的指南中探索。現在,您可以開始執行一些任務,以了解基礎知識的運作方式。

小時

總共節省的運算時間
開始使用
遠端快取 →

本頁內容