iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0

指定輸出(Outputs)

turbo.json 中設定 outputs 鍵,指明 Turborepo 在任務成功完成後應該緩存哪些文件或目錄。如果不設定這個鍵,Turborepo 將不會緩存任何文件,這意味著在後續運行中無法恢復任何文件輸出。

以下是一些常見工具的輸出設定範例:

  • Next.js:應該緩存 .next 目錄中的所有內容,但排除 .next/cache 目錄。
  • Vite:需要根據具體的構建設定來指定。
  • tsc(TypeScript):通常是 distbuild 目錄。
{
  "tasks": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**"]
    }
  }
}

更多關於使用通配符(globbing patterns)設定 outputs 的信息,可以查看 globbing 規範文檔。

指定輸入(Inputs)

inputs 鍵用於指定希望包括在任務的哈希中用於緩存的文件。默認情況下,Turborepo 會包括套件中所有被 Git 跟踪的文件。然而,您可以使用 inputs 鍵更具體地指定哈希中包含的文件。

例如,一個用於檢查 Markdown 文件中的錯別字的任務可以這樣定義:

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

如此設定後,只有 Markdown 文件的變更會導致 spell-check 任務的緩存失效。

這個功能讓你完全不使用 Turborepo 默認的輸入行為,也就是說你的 .gitignore 文件將不再被尊重,你需要確保不要用你的通配符匹配到這些文件。

如果想恢復默認行為,可以使用 $TURBO_DEFAULT$ 微語法。

恢復默認行為

通常,你會希望對任務使用默認的輸入行為。但是,你可以通過微調輸入來提高特定任務的緩存命中率,忽略已知不影響任務輸出的文件變更。

例如,下面的任務定義中,Turborepo 將使用構建任務的默認輸入行為,但會忽略 README.md 文件的變更。如果 README.md 文件發生變更,任務仍然會命中緩存:

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

這些設定有助於你更有效地利用 Turborepo 的高級功能,如緩存、並行處理和工作流管理,從而提高開發效率和專案管理的靈活性。

註冊根任務

你可以在工作空間的根目錄中使用 turbo 命令執行 package.json 中的腳本。例如,除了在每個套件中執行 lint 任務外,你還可能想在工作空間的根目錄執行一個名為 lint:root 的任務:

{
  "tasks": {
    "lint": {
      "dependsOn": ["^lint"]
    },
    "#lint:root": {}
  }
}

使用根任務的時機

  • 工作空間根目錄的代碼檢查與格式化:你的工作空間根目錄可能包含一些你想要檢查或格式化的代碼。例如,你可能想在根目錄運行 ESLint 或 Prettier。
  • 逐步遷移:在遷移至 Turborepo 的過程中,你可能會處於一個過渡階段,這時一些腳本還沒有遷移到套件中。在這種情況下,你可以創建一個根任務來開始遷移,稍後再將任務分散到各個套件。
  • 不具套件範疇的腳本:你可能有一些腳本在特定套件的上下文中沒有意義。這些腳本可以註冊為根任務,以便你仍能夠利用 turbo 進行緩存、並行處理和工作流程的目的。

高級使用案例

使用套件配置

套件配置是放置在套件內部的 turbo.json 文件。這允許套件定義自己任務的特定行為,而不影響其餘的倉庫。

在大型單一倉庫(monorepo)與多團隊協作的環境中,這使得各個團隊可以更好地控制自己的任務。要了解更多信息,可以訪問套件配置的文檔。

執行有副作用的任務

有些任務應該無論如何都要運行,比如在緩存構建後的部署腳本。對於這些任務,可以在任務定義中添加 "cache": false

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

可以並行運行的相依任務

有些任務即使依賴其他套件也可以並行運行。一個典型的例子是代碼檢查器,因為檢查器不需要等待依賴的輸出就能成功運行。

由於這個原因,你可能會誘惑定義你的 check-types 任務如下:

{
  "tasks": {
    "check-types": {} // 不正確!
}

這樣會讓你的任務並行運行 - 但沒有考慮到來源代碼的變更。這意味著你可以:

  • ui 套件中進行破壞性改變。
  • 執行 turbo check-types,在一個依賴 ui 的應用套件中命中緩存。
  • 這是不正確的,因為應用套件會顯示成功的緩存命中,儘管沒有更新以使用新的接口。在你的編輯器中手動檢查 TypeScript 錯誤可能會揭示錯誤。

因此,你需要對你的 check-types 任務定義做一個小改動:

{
  "tasks": {
    "check-types": {
      "dependsOn": ["^check-types"] // 這樣可以運行...但可能更快!
    }
}

如果你再次測試在你的 ui 套件中進行破壞性改變,你會注意到緩存行為現在是正確的。然而,任務不再並行運行了。

要同時滿足正確性和並行性的需求,你可以在任務圖中引入過渡節點(Transit Nodes):

{
  "tasks": {
    "transit": {
      "dependsOn": ["^transit"]
    },
    "check-types": {
      "dependsOn": ["transit"]
    }
}

這些過渡節點利用一個不做任何事情的任務來創建你的套件依賴之間的關係,因為它不匹配任何 package.json 中的腳本。因此,你的任務可以並行運行,同時意識到它們內部依賴的變更。

在這個例子中,我們使用了 transit 作為任務名 - 但你可以用任何不是你工作空間中已有腳本的名稱。


上一篇
那我們如何避免重複打包嗎
下一篇
Turborepo cache 機制
系列文
讓我們一起與turboRepo共舞30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言