Use Cases (更新: 2026/6/2)

Claude Code + Turborepo:高速 Monorepo 构建实战

用Claude Code设计Turborepo monorepo,覆盖tasks、缓存、CI、提示词和常见坑。

Claude Code + Turborepo:高速 Monorepo 构建实战

为什么把 Claude Code 和 Turborepo 放在一起

Monorepo 是把多个应用和共享 package 放在同一个仓库里的做法。仓库刚开始只有 apps/webpackages/ui 时很轻松,但一旦出现管理后台、文档站、共享工具函数和多个构建目标,真正麻烦的是构建顺序、依赖边界、CI 时间和缓存命中率。

Turborepo 通过任务图和缓存解决这些问题。Claude Code 的价值不是“帮我生成一个配置文件”这么简单,而是让它读取现有 package.json,解释 package 之间的依赖,检查 outputs 是否遗漏,并把 CI 命令收敛到真正受影响的范围。

本文基于 2026 年 6 月 2 日的 Turborepo v2。现在的配置应使用 tasks,不要沿用旧文章里的 pipeline。建议对照官方资料:Turborepo configurationturbo runRemote CachingClaude Code memory

站内延伸可以继续看 monorepo 管理pnpm workspace 与 Claude CodeClaude Code CI/CD 设置

目标结构和三个真实场景

本文的目标是一个小型 TypeScript monorepo,底层使用 pnpm workspace,上层用 Turborepo 管理任务。不要一开始就创建巨大的 sharedcommon 包;Claude Code 更容易遵守能用一句话解释清楚的边界。

flowchart LR
  web["apps/web\n用户端"] --> ui["packages/ui\n共享UI"]
  admin["apps/admin\n管理端"] --> ui
  web --> utils["packages/utils\n共享函数"]
  admin --> utils
  ui --> tsconfig["packages/tsconfig\nTS配置"]
  utils --> tsconfig

第一个场景是用户端和管理端共用按钮、表单和校验逻辑。把 packages/uipackages/utils 分开后,Claude Code 不容易把视觉组件、业务函数和 API 调用混在一起。

第二个场景是内容站或文档站。Landing page、文档、管理后台经常在同一个仓库中演进。如果每次 PR 都全量构建,CI 会越来越慢。--affected--filter 可以只验证变更 package 以及受它影响的 package。

第三个场景是 SaaS 或带收入转化的产品。价格页、注册表单、账户设置和管理功能往往共享小 package。只要 linttype-checktestbuild 稳定,Claude Code 修改 CTA 或 onboarding 时,CI 仍能挡住破坏共享代码的改动。

先复制最小仓库结构

先固定目录结构,再让 Claude Code 做增量修改。重点不是目录多,而是职责清楚。

acme-monorepo/
  apps/
    web/
      package.json
      src/
    admin/
      package.json
      src/
  packages/
    ui/
      package.json
      src/
    utils/
      package.json
      src/
    tsconfig/
      package.json
      base.json
  pnpm-workspace.yaml
  package.json
  turbo.json
  CLAUDE.md

pnpm-workspace.yaml 保持简单即可。

packages:
  - "apps/*"
  - "packages/*"

根目录 package.json 负责把常用命令统一成 Turborepo 命令。2026 年 6 月确认到的发布版本是 turbo@2.9.16pnpm@11.5.1,实际项目请以 lockfile 固定结果。

{
  "name": "acme-monorepo",
  "private": true,
  "packageManager": "pnpm@11.5.1",
  "scripts": {
    "dev": "turbo dev",
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "type-check": "turbo run type-check",
    "check": "turbo run lint type-check test build",
    "check:affected": "turbo run lint type-check test build --affected"
  },
  "devDependencies": {
    "turbo": "^2.9.16",
    "typescript": "^5.8.3"
  }
}

内部 package 用 workspace:*,明确告诉包管理器从当前 workspace 解析,而不是去 registry 找同名包。

{
  "name": "@acme/ui",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "scripts": {
    "build": "tsc -p tsconfig.json",
    "lint": "eslint src --max-warnings=0",
    "type-check": "tsc -p tsconfig.json --noEmit",
    "test": "vitest run"
  },
  "devDependencies": {
    "@acme/tsconfig": "workspace:*",
    "typescript": "^5.8.3",
    "vitest": "^3.1.0",
    "eslint": "^9.25.0"
  }
}

turbo.json 要写清 tasks、outputs 和 env

根目录的 turbo.json 是整个仓库的任务契约。tasks 下的每个键,都会匹配各 package 的同名脚本。^build 的意思是先构建依赖 package,再构建当前 package。

{
  "$schema": "https://turborepo.dev/schema.json",
  "globalDependencies": ["pnpm-lock.yaml", "tsconfig.base.json", ".env.example"],
  "globalEnv": ["NODE_ENV"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**", "out/**"]
    },
    "lint": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "type-check": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

outputs 是可以从缓存恢复的产物。写少了,构建虽然成功但缓存没有价值;写多了,又会把临时文件和框架内部缓存带进 CI。对于 Next.js,排除 .next/cache/** 通常更稳。

如果某个应用有特殊输出,可以在 package 内放 turbo.json。数组字段默认会替换根配置;想追加时,把 $TURBO_EXTENDS$ 放在数组第一项。

{
  "extends": ["//"],
  "tasks": {
    "build": {
      "outputs": ["$TURBO_EXTENDS$", ".next/**", "!.next/cache/**"],
      "env": ["NEXT_PUBLIC_API_URL"]
    }
  }
}

CI 和验证命令要固定

Turborepo 在 CI 中最容易体现价值,但 --affected 需要完整的 Git 比较历史。GitHub Actions 里建议设置 fetch-depth: 0,否则浅克隆可能让所有 package 都被判定为变更。

name: turbo-ci

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  verify:
    runs-on: ubuntu-latest
    env:
      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
      TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@v4
        with:
          version: 11.5.1
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm turbo run lint type-check test build --affected
      - run: pnpm turbo run build --dry=json > turbo-plan.json
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: turbo-plan
          path: turbo-plan.json

使用 Remote Cache 时,本地先执行 pnpm dlx turbo loginpnpm dlx turbo link,CI 中通过 secret 提供 TURBO_TOKENTURBO_TEAM。同时要记住,日志也可能成为缓存产物,所以构建脚本不要打印 API key、用户数据或 session token。

把常用命令写进 CLAUDE.md,Claude Code 就不需要每次重新猜。

pnpm turbo run build --dry=json
pnpm turbo run build --filter=@acme/web...
pnpm turbo run test --filter=...[origin/main]
pnpm turbo run lint --filter=!./apps/docs
pnpm turbo run build --cache=local:rw,remote:r
pnpm turbo run build --force

给 Claude Code 的提示词模板

不要只说“帮我配置 Turborepo”。要把边界、禁止事项和验证命令一次说清楚。

这个仓库是 Turborepo v2 + pnpm workspace monorepo。

边界:
- apps/* 是可部署应用。
- packages/ui 只放视觉组件。
- packages/utils 只放与框架无关的函数。
- packages/* 不能依赖 apps/*。
- turbo.json 必须使用 tasks,不要使用 pipeline。

任务:
1. 读取 package.json 和 turbo.json,解释任务依赖图。
2. 指出缓存 outputs 缺失或可疑的地方。
3. 如需修改,请用最小安全差异。
4. 最后运行这些命令并报告结果:

pnpm turbo run lint type-check test build --affected
pnpm turbo run build --dry=json

这个模板能减少 AI 常见的大范围重写。它也能阻止一些危险提案,比如在 packages/ui 写 HTTP 调用、在 packages/utils 里依赖 Next.js、或者把全仓库构建当成唯一 CI 策略。

常见坑

第一,复制旧的 pipeline 示例。Turborepo v2 使用 tasks。迁移旧仓库时,可以让 Claude Code 对照官方文档解释每一个变更。

第二,缓存范围过大。不要把 node_modules/**、临时日志或不可部署的内部缓存写进 outputs。缓存构建产物,不要缓存整个工作区。

第三,在浅克隆中使用 --affected。如果 CI 没有 base 和 head 的历史,Turborepo 无法计算正确范围,结果可能退化成全量任务。

第四,一次让 Claude Code 做太多事。先引入 Turborepo,再整理 root scripts,最后接入 CI。不要把 package 拆分、ESLint 升级和依赖升级混在同一个请求里。

第五,过度共用。巨大的 packages/shared 会让每次变更都像全局变更。uiutilscontractstsconfig 这种小而明确的 package 更容易维护。

收益导线和下一步

Turborepo 不只是加速工具,它也能保护收入路径。内容站可以在构建失败时停止发布,SaaS 可以在同一个流程中验证价格页、注册、账户设置和管理功能。团队开发中,CI 缩短也会减少 review 等待时间。

ClaudeCodeLab 可以帮助团队把这些规则落成可重复流程,包括 CLAUDE.md、package 边界、CI 命令、review prompt 和发布规则。自学可以继续读 monorepo 管理CI/CD 设置。团队落地可以从 training / consultation 开始。

实际试用结果

Masa 把这套方式应用到两个 Vite 应用和一个共享 UI package 的小型仓库中。第一次运行会执行所有任务,之后 buildtype-check 能看到缓存命中。最初的问题是 outputs 太宽,把框架内部缓存也存进了 CI artifact,导致结果很吵。最终保留下来的就是本文这种方式:v2 tasks、收窄的 outputs、受影响范围验证,以及先审查边界再改文件的 Claude Code 提示词。

#Claude Code #Turborepo #monorepo #构建工具 #性能
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。