Turborepo 单体仓库任务编排

FreeGuideOnline 最新 2026-07-09

bash mkdir my-monorepo && cd my-monorepo pnpm init


创建 `pnpm-workspace.yaml`,定义工作区包位置:

```yaml
packages:
  - "apps/*"
  - "packages/*"

手动创建目录结构:

my-monorepo/
├── apps/
│   ├── web/
│   └── docs/
├── packages/
│   └── ui/
├── pnpm-workspace.yaml
├── package.json
└── turbo.json

每个子包内部都有各自的 package.json 和代码,此处不展开。关键是要让它们包含常见的 scripts,如 buildtestlint

2. 安装 Turborepo

全局安装或作为 devDependency 添加:

pnpm add -D turbo

根目录 package.json 添加便捷脚本:

{
  "scripts": {
    "build": "turbo run build",
    "test": "turbo run test",
    "lint": "turbo run lint",
    "dev": "turbo run dev --parallel"
  }
}

这样你就可以通过根目录调用 pnpm build 等命令来运行 Turborepo 编排的任务。

核心概念:任务管道 (Pipeline)

Turborepo 的行为由根目录的 turbo.json 配置文件控制。核心就是 pipeline 字段,它声明了仓库中每个任务应该如何被运行、依赖哪些任务。

最小配置示例

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {},
    "lint": {}
  }
}

该配置告诉 Turborepo:

  • 所有包的 build 脚本被纳入编排,其产出目录为 dist.next(用于缓存)。
  • testlint 没有产出,但也会被编排。

声明依赖关系

真实场景中,任务之间往往存在先后依赖。例如 testlint 应在 build 之前运行;如果一个包依赖另一个包的构建产物,则对应 build 任务需要按依赖拓扑顺序执行。这些都可以通过 dependsOn 声明:

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"]
    },
    "lint": {},
    "dev": {
      "cache": false
    }
  }
}
  • dependsOn: ["^build"]:表示一个包的 build 任务必须等待它所依赖(在 package.json 中声明)的所有包的 build 任务完成。这保证了构建顺序的正确性。
  • dependsOn: ["build"]:表示当前任务需要等待同包内build 任务完成。例如,test 必须在 build 之后运行。
  • cache: false:对于 dev 这类服务器实时监听的任务,我们通常禁用缓存。

缓存机制:跳过重复工作

Turborepo 会根据输入文件的内容哈希任务配置来判断是否可以复用缓存。当你运行 turbo run build 时,如果源代码未改变,Turborepo 将直接显示 "FULL TURBO" 并跳过执行,输出可从缓存恢复。

配置输入和输出

为了准确计算哈希,需要在 pipeline 中指定任务的 inputs(默认是所有工作区文件)和 outputs。建议显式声明,提高缓存命中率:

{
  "pipeline": {
    "build": {
      "inputs": ["src/**/*.ts", "src/**/*.tsx", "tsconfig.json"],
      "outputs": ["dist/**"]
    }
  }
}

Turborepo 还会自动包含包内的 package.json 和配置文件中声明的全局依赖文件(如根目录 turbo.json 本身)。

远程缓存

本地缓存仅对当前机器有效。使用 Turborepo 的远程缓存功能(如 Vercel 提供的免费远程缓存服务或自建服务),团队成员和 CI 环境可以共享缓存。只需在项目根目录设置环境变量并连接:

npx turbo login  # 登录 Vercel 账号
npx turbo link   # 链接到远程缓存

# 或手动设置自建缓存服务器 URL
TURBO_TOKEN=your_token TURBO_API=http://your-cache-server turbo run build

配置好后,CI 中的首次构建仍会执行完整编译,但后续任何人在任何分支上的相同构建都可能命中远程缓存,极大加速迭代。

并行执行与依赖拓扑

Turborepo 自动根据包的依赖树和 dependsOn 规则生成有向无环图(DAG),并以最大并行度执行任务。你无需手动管理 --parallel--concurrency。默认最大并发数由 CPU 核心数决定,你也可以通过 --concurrency=10 调整。

turbo run build --concurrency=8

对于不冲突的任务,例如所有包的 lint,它们之间通常没有交叉依赖,会完全并行运行。这正是 turbonx 原生 nx.jsonlerna 更简洁高效的地方。

环境变量与全局依赖

某些任务可能依赖于环境变量(如 NODE_ENV)。默认情况下,Turborepo 不会将环境变量纳入哈希计算,这可能导致缓存错误。你可以在 turbo.json 全局或任务级别声明 globalDependenciesglobalEnv

{
  "globalEnv": ["NODE_ENV", "API_URL"],
  "pipeline": {
    "build": {
      "env": ["DATABASE_URL"],
      "outputs": ["dist/**"]
    }
  }
}
  • globalEnv:对所有任务生效。
  • env:仅对当前任务生效。

请注意,若添加了新的环境变量,turbo 会自动将其纳入哈希;你也可以通过 globalDependencies 声明文件路径(如 .env)来监视环境文件的变化。

高级用法:从现有 Monorepo 迁移

如果你的仓库已经使用 Yarn/NPM/Lerna 等工具管理,集成 Turborepo 非常简单:

  1. 安装 turbo 开发依赖。
  2. 从最简单的 turbo.json 开始:
{
  "pipeline": {
    "build": {},
    "test": {},
    "lint": {}
  }
}