turborepo

turborepo

熱門

Turborepo monorepo 建置系統指南。觸發條件:turbo.json、任務流程管道(task pipelines)、dependsOn、快取(caching)、遠端快取(remote cache)、"turbo" CLI、--filter、--affected、CI 最佳化、環境變數、內部套件(internal packages)、monorepo 架構/最佳實踐以及邊界限制(boundaries)。 當使用者符合以下情境時使用:設定任務/工作流程/流程管道、建立套件、建置 monorepo、在應用程式之間共用程式碼、執行已變更/受影響的套件、除錯快取問題,或專案中含有 apps/packages 目錄。

5514星標
0分支
更新於 2026/7/11
SKILL.md
唯讀
名稱
turborepo
描述

Turborepo monorepo 建置系統指南。觸發條件:turbo.json、任務流程管道(task pipelines)、dependsOn、快取(caching)、遠端快取(remote cache)、"turbo" CLI、--filter、--affected、CI 最佳化、環境變數、內部套件(internal packages)、monorepo 架構/最佳實踐以及邊界限制(boundaries)。 當使用者符合以下情境時使用:設定任務/工作流程/流程管道、建立套件、建置 monorepo、在應用程式之間共用程式碼、執行已變更/受影響的套件、除錯快取問題,或專案中含有 apps/packages 目錄。

Turborepo Skill

適用於 JavaScript/TypeScript monorepo 的建置系統。Turborepo 會快取任務輸出,並根據相依性圖表(dependency graph)平行執行任務。

重要:優先使用 Package Tasks,而非 Root Tasks

請優先使用套件任務(Package tasks),而非根目錄任務(Root Tasks)。

建立任務/腳本/流程管道時,您必須預設使用套件任務:

  1. 將腳本新增至各個相關套件的 package.json
  2. 在根目錄的 turbo.json 中註冊該任務
  3. 根目錄的 package.json 僅透過 turbo run <task> 委派執行

切勿在根目錄的 package.json 中編寫可以放在套件內的任務邏輯。這會破壞 Turborepo 的平行處理能力。

// 建議作法:將腳本放在各套件中
// apps/web/package.json
{ "scripts": { "build": "next build", "lint": "eslint .", "test": "vitest" } }

// apps/api/package.json
{ "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } }

// packages/ui/package.json
{ "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } }
// turbo.json - 註冊任務
{
  "tasks": {
    "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
    "lint": {},
    "test": { "dependsOn": ["build"] }
  }
}
// 根目錄 package.json - 僅進行委派,無任務邏輯
{
  "scripts": {
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test"
  }
}
// 請勿這樣做 - 會破壞平行處理能力
// 根目錄 package.json
{
  "scripts": {
    "build": "cd apps/web && next build && cd ../api && tsc",
    "lint": "eslint apps/ packages/",
    "test": "vitest"
  }
}

根目錄任務(//#taskname僅適用於確實無法存在於套件中的任務,例如 Vitest Projects 的 //#test、全域釋出腳本(release scripts),或是本身不會呼叫 turbo 的工具鏈。

次要規則:turbo run vs turbo

在程式碼或設定檔中撰寫指令時,請一律使用 turbo run

// package.json - 一律使用 "turbo run"
{
  "scripts": {
    "build": "turbo run build"
  }
}
# CI 工作流程 - 一律使用 "turbo run"
- run: turbo run build --affected

簡寫格式 turbo <tasks> 僅適用於由人類或 Agent 在終端機直接輸入的一次性指令。切勿將 turbo build 寫入 package.json、CI 或腳本中。

快速決策樹

「我需要設定任務」

設定任務?
├─ 定義任務相依性 → references/configuration/tasks.md
├─ Lint/型別檢查 (平行處理 + 快取) → 使用 Transit Nodes 模式 (見下方)
├─ 指定建置輸出 → references/configuration/tasks.md#outputs
├─ 處理環境變數 → references/environment/RULE.md
├─ 設定開發/監控任務 → references/configuration/tasks.md#persistent
├─ 特定套件設定 → references/configuration/RULE.md#package-configurations
└─ 全域設定 (cacheDir, daemon) → references/configuration/global-options.md

「我的快取沒有生效」

快取問題?
├─ 任務已執行但未還原輸出 → 缺少 `outputs` 鍵值
├─ 意料之外的快取未命中 (Cache miss) → references/caching/gotchas.md
├─ 需要除錯雜湊輸入值 (Hash inputs) → 使用 --summarize 或 --dry
├─ 想要完全跳過快取 → 使用 --force 或 cache: false
├─ 遠端快取 (Remote cache) 未生效 → references/caching/remote-cache.md
└─ 環境變數導致未命中 → references/environment/gotchas.md

「我只想執行有變更的套件」

只執行變更部分?
├─ 變更的套件 + 相依於它的套件 (推薦) → turbo run build --affected
├─ 自訂基準分支 → --affected --affected-base=origin/develop
├─ 手動 Git 比對 → --filter=...[origin/main]
└─ 檢視所有篩選選項 → references/filtering/RULE.md

--affected 是只執行已變更套件的主要方式。 它會自動與預設分支比對,並包含受影響的相依套件。

「我想要篩選套件」

篩選套件?
├─ 僅變更的套件 → --affected (見上方)
├─ 依套件名稱 → --filter=web
├─ 依目錄 → --filter=./apps/*
├─ 套件 + 前置相依套件 → --filter=web...
├─ 套件 + 後續受影響套件 → --filter=...web
└─ 複雜組合 → references/filtering/patterns.md

「環境變數無法正常運作」

環境變數問題?
├─ 變更在執行階段 (Runtime) 無法讀取 → 嚴格模式篩選 (預設)
├─ 快取命中但帶有錯誤環境變數 → 變數未列於 `env` 鍵值中
├─ .env 變更未引發重新建置 → .env 未列於 `inputs`
├─ 缺少 CI 環境變數 → references/environment/gotchas.md
└─ 框架專用變數 (NEXT_PUBLIC_*) → 透過推斷自動包含

「我需要設定 CI」

CI 設定?
├─ GitHub Actions → references/ci/github-actions.md
├─ Vercel 部署 → references/ci/vercel.md
├─ CI 中的遠端快取 → references/caching/remote-cache.md
├─ 僅建置有變更的套件 → --affected 旗標
├─ 跳過不必要的建置 → turbo-ignore (references/cli/commands.md)
└─ 無變更時跳過容器設定 → turbo-ignore

「我想在開發時監控檔案變更」

監控模式 (Watch mode)?
├─ 變更時重新執行任務 → turbo watch (references/watch/RULE.md)
├─ 帶有相依關係的開發伺服器 → 使用 `with` 鍵值 (references/configuration/tasks.md#with)
├─ 相依套件變更時重啟開發伺服器 → 使用 `interruptible: true`
└─ 持續執行的開發任務 → 使用 `persistent: true`

「我需要建立/組織套件結構」

套件建立/架構?
├─ 建立內部套件 → references/best-practices/packages.md
├─ 儲存庫結構 → references/best-practices/structure.md
├─ 相依性管理 → references/best-practices/dependencies.md
├─ 最佳實踐總覽 → references/best-practices/RULE.md
├─ JIT 與預先編譯 (Compiled) 套件 → references/best-practices/packages.md#compilation-strategies
└─ 在應用程式之間共用程式碼 → references/best-practices/RULE.md#package-types

「我應該如何組織 Monorepo 架構?」

Monorepo 架構?
├─ 標準配置 (apps/, packages/) → references/best-practices/RULE.md
├─ 套件類型 (apps vs libraries) → references/best-practices/RULE.md#package-types
├─ 建立內部套件 → references/best-practices/packages.md
├─ TypeScript 設定 → references/best-practices/structure.md#typescript-configuration
├─ ESLint 設定 → references/best-practices/structure.md#eslint-configuration
├─ 相依性管理 → references/best-practices/dependencies.md
└─ 強制執行套件邊界 → references/boundaries/RULE.md

「我想強制執行架構邊界」

強制執行邊界?
├─ 檢查違反規則項 → turbo boundaries
├─ 為套件打上標籤 → references/boundaries/RULE.md#tags
├─ 限制套件之間的匯入關係 → references/boundaries/RULE.md#rule-types
└─ 防止跨套件檔案直接匯入 → references/boundaries/RULE.md

關鍵反模式 (Critical Anti-Patterns)

在程式碼中使用 turbo 簡寫

建議在 package.json 腳本與 CI 流程管道中使用 turbo run 簡寫格式 turbo <task> 主要設計給互動式終端機手動使用。

// 錯誤 - 在 package.json 中使用簡寫
{
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev"
  }
}

// 正確
{
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev"
  }
}
# 錯誤 - 在 CI 中使用簡寫
- run: turbo build --affected

# 正確
- run: turbo run build --affected

根目錄腳本繞過 Turbo

根目錄 package.json 中的腳本必須委派給 turbo run,而不是直接執行任務。

// 錯誤 - 完全繞過 turbo
{
  "scripts": {
    "build": "bun build",
    "dev": "bun dev"
  }
}

// 正確 - 委派給 turbo
{
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev"
  }
}

使用 && 串接 Turbo 任務

不要使用 && 串接 turbo 任務,讓 turbo 負責排程協調。

// 錯誤 - turbo 任務未使用 turbo run
{
  "scripts": {
    "changeset:publish": "bun build && changeset publish"
  }
}

// 正確
{
  "scripts": {
    "changeset:publish": "turbo run build && changeset publish"
  }
}

手動建置相依套件的 prebuild 腳本

prebuild 這樣手動建置其他套件的腳本,會繞過 Turborepo 的相依性圖表。

// 錯誤 - 手動建置相依套件
{
  "scripts": {
    "prebuild": "cd ../../packages/types && bun run build && cd ../utils && bun run build",
    "build": "next build"
  }
}

然而,修復方式取決於是否已宣告 workspace 相依性:

  1. 若已宣告相依性(例如 package.json 中的 "@repo/types": "workspace:*"),請直接移除 prebuild 腳本。Turbo 的 dependsOn: ["^build"] 會自動處理建置順序。

  2. 若未宣告相依性,則 prebuild 的存在是因為沒有相依關係時 ^build 不會自動觸發。修復步驟為:

    • 在 package.json 新增相依性:"@repo/types": "workspace:*"
    • 接著移除 prebuild 腳本
// 正確 - 宣告相依性,讓 turbo 處理建置順序
// package.json
{
  "dependencies": {
    "@repo/types": "workspace:*",
    "@repo/utils": "workspace:*"
  },
  "scripts": {
    "build": "next build"
  }
}

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

核心觀念: ^build 只會執行列為相依套件中的 build 任務。如果沒有宣告相依性 = 不會自動排序建置。

過於寬鬆的 globalDependencies

globalDependencies 會透過**全域雜湊(global hash)**影響所有套件中的所有任務 — 即使在 inputs 中使用否定匹配(negation globs),任務也無法排除特定檔案。請務必指定明確的範圍。

// 錯誤 - 範圍過大,影響所有雜湊值
{
  "globalDependencies": ["**/.env.*local"]
}

// 較佳 - 移至任務層級的 inputs
{
  "globalDependencies": [".env"],
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": ["dist/**"]
    }
  }
}

啟用 futureFlags.globalConfiguration 後此問題可獲得緩解,因為 global.inputs 檔案會直接合併至各任務的 inputs(而非納入全域雜湊)。任務即可排除特定檔案:

// 最佳 - 使用 global.inputs 並搭配個別任務排除規則
{
  "futureFlags": { "globalConfiguration": true },
  "global": {
    "inputs": [".env"]
  },
  "tasks": {
    "build": { "outputs": ["dist/**"] },
    "lint": {
      "inputs": ["$TURBO_DEFAULT$", "!$TURBO_ROOT$/.env"]
    }
  }
}

重複的任務設定

檢查跨任務之間是否有可以整合收攏的重複設定。Turborepo 支援共用設定模式。

// 錯誤 - 跨任務重複設定 env 與 inputs
{
  "tasks": {
    "build": {
      "env": ["API_URL", "DATABASE_URL"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"]
    },
    "test": {
      "env": ["API_URL", "DATABASE_URL"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"]
    },
    "dev": {
      "env": ["API_URL", "DATABASE_URL"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "cache": false,
      "persistent": true
    }
  }
}

// 較佳 - 使用 globalEnv 與 globalDependencies 設定共用項目
{
  "globalEnv": ["API_URL", "DATABASE_URL"],
  "globalDependencies": [".env*"],
  "tasks": {
    "build": {},
    "test": {},
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

何時使用全域(global)與任務層級(task-level):

  • globalEnv / globalDependencies - 影響所有任務,適用於真正全域共用的設定
  • 任務層級的 env / inputs - 僅在特定任務需要時使用

注意:大型 env 陣列「並非」反模式

即使 env 陣列很大(包含 50 個以上的變數),也不是問題。這通常代表使用者非常仔細地宣告了建置過程中所相依的環境變數。請勿將其標記為問題。

<!-- truncated for translation batch; full body continues in source -->