名称: turborepo 描述: 实施 Turborepo 的指南 - 一个针对 JavaScript 和 TypeScript monorepos 的高性能构建系统。在设置 monorepos、优化构建性能、实施任务管道、配置缓存策略或跨多个包编排任务时使用。 许可证: MIT 版本: 1.0.0
Turborepo 技能
Turborepo 是一个针对 JavaScript 和 TypeScript monorepos 优化的高性能构建系统,使用 Rust 编写。它提供智能缓存、任务编排和远程执行功能,以显著加速开发工作流程。
参考
https://turborepo.com/llms.txt
何时使用此技能
在以下情况下使用此技能:
- 设置具有多个包的新 monorepo
- 优化现有 monorepos 中的构建性能
- 跨包实施任务管道
- 配置智能缓存策略
- 为团队设置远程缓存
- 编排具有依赖感知的任务
- 将 monorepo 与 CI/CD 管道集成
- 从 Lerna、Nx 或其他 monorepo 工具迁移
- 构建微前端或共享库
- 管理工作区依赖
核心概念
1. Monorepo 架构
Turborepo 将代码组织到单个存储库中的包内:
- 根包: 包含工作区配置
- 内部包: 共享库、实用工具、配置
- 应用程序: 前端应用、后端服务等
- 工作区: npm/yarn/pnpm 工作区配置
2. 任务管道
任务在依赖图中组织:
- 任务依赖: 定义执行顺序(构建先于测试)
- 包依赖: 尊重内部包关系
- 并行执行: 同时运行独立任务
- 拓扑排序: 按正确依赖顺序执行任务
3. 智能缓存
Turborepo 根据输入缓存任务输出:
- 本地缓存: 在本地机器上存储输出
- 远程缓存: 跨团队/CI 共享缓存(Vercel 或自定义)
- 基于内容的哈希: 仅当输入更改时重新运行
- 缓存恢复: 从缓存中即时完成任务
4. 任务输出
定义缓存内容:
- 构建产物 (dist/, build/)
- 测试结果
- 生成的文件
- 类型定义
安装
先决条件
# 需要 Node.js 18+ 和包管理器
node --version # v18.0.0+
全局安装
# npm
npm install turbo --global
# yarn
yarn global add turbo
# pnpm
pnpm add turbo --global
# bun
bun add turbo --global
按项目安装
# npm
npm install turbo --save-dev
# yarn
yarn add turbo --dev
# pnpm
pnpm add turbo --save-dev
# bun
bun add turbo --dev
项目设置
创建新 Monorepo
使用官方示例:
npx create-turbo@latest
交互式提示将询问:
- 项目名称
- 包管理器 (npm/yarn/pnpm/bun)
- 示例模板选择
手动设置
1. 初始化工作区:
// package.json (根)
{
"name": "my-turborepo",
"private": true,
"workspaces": ["apps/*", "packages/*"],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
}
}
2. 创建目录结构:
my-turborepo/
├── apps/
│ ├── web/ # Next.js 应用
│ └── docs/ # 文档站点
├── packages/
│ ├── ui/ # 共享 UI 组件
│ ├── config/ # 共享配置 (ESLint, TS)
│ └── tsconfig/ # 共享 TypeScript 配置
├── turbo.json # Turborepo 配置
└── package.json # 根 package.json
3. 创建 turbo.json:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {},
"test": {
"dependsOn": ["build"]
}
}
}
配置 (turbo.json)
基本结构
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env", "tsconfig.json"],
"globalEnv": ["NODE_ENV"],
"pipeline": {
// 任务定义
}
}
管道配置
带依赖的任务:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"env": ["NODE_ENV", "API_URL"]
}
}
}
关键属性:
dependsOn: 先运行的任务["^build"]: 先运行依赖项的构建["build"]: 先运行自身构建["^build", "lint"]: 运行依赖项构建和自身 lint
outputs: 缓存的文件/目录inputs: 覆盖输入检测(默认:所有跟踪文件)cache: 启用/禁用缓存(默认:true)env: 影响输出的环境变量persistent: 保持任务运行(用于开发服务器)outputMode: 控制输出显示
任务依赖模式
拓扑 (^):
{
"build": {
"dependsOn": ["^build"] // 先运行依赖项的构建
}
}
常规:
{
"deploy": {
"dependsOn": ["build", "test"] // 先运行自身构建和测试
}
}
组合:
{
"test": {
"dependsOn": ["^build", "lint"] // 依赖项构建,然后自身 lint
}
}
输出模式
{
"pipeline": {
"build": {
"outputMode": "full" // 显示所有输出
},
"dev": {
"outputMode": "hash-only" // 仅显示缓存哈希
},
"test": {
"outputMode": "new-only" // 仅显示新输出
},
"lint": {
"outputMode": "errors-only" // 仅显示错误
}
}
}
环境变量
全局环境变量:
{
"globalEnv": ["NODE_ENV", "CI"],
"globalDependencies": [".env", ".env.local"]
}
每任务环境变量:
{
"pipeline": {
"build": {
"env": ["NEXT_PUBLIC_API_URL", "DATABASE_URL"],
"passThroughEnv": ["CUSTOM_VAR"] // 传递而不哈希
}
}
}
命令
turbo run
跨包运行任务:
# 在所有包中运行构建
turbo run build
# 运行多个任务
turbo run build test lint
# 在特定包中运行
turbo run build --filter=web
turbo run build --filter=@myorg/ui
# 在匹配模式的包中运行
turbo run build --filter='./apps/*'
# 强制执行(跳过缓存)
turbo run build --force
# 从特定目录运行
turbo run build --filter='[./apps/web]'
# 运行带依赖
turbo run build --filter='...^web'
# 并行执行控制
turbo run build --concurrency=3
turbo run build --concurrency=50%
# 出错继续
turbo run test --continue
# 干运行
turbo run build --dry-run
# 输出控制
turbo run build --output-logs=new-only
turbo run build --output-logs=hash-only
turbo run build --output-logs=errors-only
turbo run build --output-logs=full
turbo prune
创建 monorepo 的子集:
# 修剪特定应用
turbo prune --scope=web
# 带 Docker 修剪
turbo prune --scope=api --docker
# 输出到自定义目录
turbo prune --scope=web --out-dir=./deploy
使用场景:
- Docker 构建(仅包括必要包)
- 部署特定应用
- 减少 CI/CD 上下文大小
turbo gen
在 monorepo 中生成代码:
# 生成新包
turbo gen workspace
# 从自定义生成器生成
turbo gen my-generator
# 列出可用生成器
turbo gen --list
turbo link
将本地存储库链接到远程缓存:
# 链接到 Vercel
turbo link
# 取消链接
turbo unlink
turbo login
使用 Vercel 认证:
turbo login
turbo ls
列出 monorepo 中的包:
# 列出所有包
turbo ls
# JSON 输出
turbo ls --json
过滤
按包名过滤
# 单个包
turbo run build --filter=web
# 多个包
turbo run build --filter=web --filter=api
# 作用域包
turbo run build --filter=@myorg/ui
按模式过滤
# 所有应用
turbo run build --filter='./apps/*'
# 模式匹配
turbo run build --filter='*-ui'
按目录过滤
# 从特定目录
turbo run build --filter='[./apps/web]'
按 Git 过滤
# 自 main 后更改
turbo run build --filter='[main]'
# 自 HEAD~1 后更改
turbo run build --filter='[HEAD~1]'
# 工作目录中更改
turbo run test --filter='...[HEAD]'
按依赖过滤
# 包及其依赖
turbo run build --filter='...web'
# 包的依赖仅
turbo run build --filter='...^web'
# 包及其依赖项
turbo run test --filter='ui...'
# 包的依赖项仅
turbo run test --filter='^ui...'
缓存策略
本地缓存
默认启用,存储在 ./node_modules/.cache/turbo
缓存行为:
{
"pipeline": {
"build": {
"outputs": ["dist/**"], // 缓存 dist 目录
"cache": true // 启用缓存(默认)
},
"dev": {
"cache": false // 为开发服务器禁用
}
}
}
清除缓存:
# 清除 Turbo 缓存
rm -rf ./node_modules/.cache/turbo
# 或使用 turbo 命令
turbo run build --force # 跳过此运行的缓存
远程缓存
跨团队和 CI 共享缓存:
1. 链接到 Vercel(推荐):
turbo login
turbo link
2. 自定义远程缓存:
// .turbo/config.json
{
"teamid": "team_123",
"apiurl": "https://cache.example.com",
"token": "your-token"
}
优势:
- 跨团队共享构建
- 加速 CI/CD
- 一致的构建
- 减少计算成本
缓存签名
缓存失效时:
- 源文件更改
- 依赖更改
- 环境变量更改(如指定)
- 全局依赖更改
- 任务配置更改
控制输入:
{
"pipeline": {
"build": {
"inputs": ["src/**/*.ts", "!src/**/*.test.ts"],
"env": ["NODE_ENV"]
}
}
}
工作区模式
包类型
1. 内部包 (packages/*):
// packages/ui/package.json
{
"name": "@myorg/ui",
"version": "0.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"lint": "eslint ."
}
}
2. 应用 (apps/*):
// apps/web/package.json
{
"name": "web",
"version": "1.0.0",
"private": true,
"dependencies": {
"@myorg/ui": "*",
"next": "latest"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
依赖管理
工作区协议 (pnpm/yarn):
{
"dependencies": {
"@myorg/ui": "workspace:*"
}
}
版本协议 (npm):
{
"dependencies": {
"@myorg/ui": "*"
}
}
共享配置
ESLint 配置包:
// packages/eslint-config/index.js
module.exports = {
extends: ["next", "prettier"],
rules: {
// 共享规则
}
}
TypeScript 配置包:
// packages/tsconfig/base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
使用:
// apps/web/tsconfig.json
{
"extends": "@myorg/tsconfig/base.json",
"compilerOptions": {
"jsx": "preserve"
}
}
CI/CD 集成
GitHub Actions
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: 安装依赖
run: npm install
- name: 构建
run: npx turbo run build
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- name: 测试
run: npx turbo run test
GitLab CI
image: node:18
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .turbo/
build:
stage: build
script:
- npm install
- npx turbo run build
variables:
TURBO_TOKEN: $TURBO_TOKEN
TURBO_TEAM: $TURBO_TEAM
Docker
FROM node:18-alpine AS base
# 修剪工作区
FROM base AS builder
RUN npm install -g turbo
COPY . .
RUN turbo prune --scope=web --docker
# 安装依赖
FROM base AS installer
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/package-lock.json ./package-lock.json
RUN npm install
# 构建
COPY --from=builder /app/out/full/ .
RUN npx turbo run build --filter=web
# 运行器
FROM base AS runner
COPY --from=installer /app/apps/web/.next/standalone ./
COPY --from=installer /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=installer /app/apps/web/public ./apps/web/public
CMD node apps/web/server.js
优化提示
- 在 CI 中使用远程缓存:
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- 缓存 node_modules:
- uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- 仅运行受影响任务:
turbo run build test --filter='...[origin/main]'
框架集成
Next.js
// apps/web/package.json
{
"name": "web",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "latest"
}
}
turbo.json:
{
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Vite
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
NuxtJS
{
"pipeline": {
"build": {
"outputs": [".output/**", ".nuxt/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
开发工具集成
TypeScript
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "*.tsbuildinfo"]
},
"typecheck": {
"dependsOn": ["^build"]
}
}
}
ESLint
{
"pipeline": {
"lint": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Jest / Vitest
{
"pipeline": {
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
}
}
}
Prisma
{
"pipeline": {
"db:generate": {
"cache": false
},
"db:push": {
"cache": false
}
}
}
最佳实践
1. 结构化您的 Monorepo
my-monorepo/
├── apps/ # 应用
│ ├── web/ # 前端应用
│ ├── api/ # 后端 API
│ └── docs/ # 文档
├── packages/ # 共享包
│ ├── ui/ # UI 组件
│ ├── config/ # 共享配置
│ ├── utils/ # 实用工具
│ └── tsconfig/ # TS 配置
├── tooling/ # 开发工具
│ ├── eslint-config/
│ └── prettier-config/
└── turbo.json
2. 定义清晰的任务依赖
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {
"dependsOn": ["^build"]
},
"deploy": {
"dependsOn": ["build", "test", "lint"]
}
}
}
3. 优化缓存配置
- 缓存构建输出,而非源文件
- 在输出中包含所有生成的文件
- 排除缓存目录(例如,
.next/cache) - 为开发服务器禁用缓存
{
"pipeline": {
"build": {
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**",
"storybook-static/**"
]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
4. 明智使用环境变量
{
"globalEnv": ["NODE_ENV", "CI"],
"pipeline": {
"build": {
"env": ["NEXT_PUBLIC_API_URL"],
"passThroughEnv": ["DEBUG"] // 不影响缓存
}
}
}
5. 利用远程缓存
- 为所有团队成员启用
- 在 CI/CD 中配置
- 显著减少构建时间
- 对大团队特别有益
6. 有效使用过滤器
# 仅构建更改的包
turbo run build --filter='...[origin/main]'
# 构建特定应用及其依赖
turbo run build --filter='...web'
# 仅测试受影响的包
turbo run test --filter='...[HEAD^1]'
7. 一致组织脚本
根 package.json:
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean && rm -rf node_modules"
}
}
8. 处理持续任务
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true // 保持运行
}
}
}
常见模式
全栈应用
apps/
├── web/ # Next.js 前端
│ └── package.json
├── api/ # Express 后端
│ └── package.json
└── mobile/ # React Native
└── package.json
packages/
├── ui/ # 共享 UI 组件
├── database/ # 数据库客户端/迁移
├── types/ # 共享 TypeScript 类型
└── config/ # 共享配置
共享组件库
packages/
├── ui/ # 组件库
│ ├── src/
│ ├── package.json
│ └── tsconfig.json
└── ui-docs/ # Storybook
├── .storybook/
├── stories/
└── package.json
微前端
apps/
├── shell/ # 容器应用
├── dashboard/ # 仪表板 MFE
└── settings/ # 设置 MFE
packages/
├── shared-ui/ # 共享组件
└── router/ # 路由逻辑
故障排除
缓存问题
问题: 任务应使用缓存时未使用
# 检查导致缓存未命中的原因
turbo run build --dry-run=json
# 强制重建
turbo run build --force
# 清除缓存
rm -rf ./node_modules/.cache/turbo
问题: 缓存太大
# 在 turbo.json 中限制缓存大小
{
"cacheDir": ".turbo",
"cacheSize": "50gb"
}
依赖问题
问题: 找不到内部包
# 确保工作区设置正确
npm install
# 检查包名称匹配
npm ls @myorg/ui
# 重新构建依赖
turbo run build --filter='...web'
任务执行问题
问题: 任务运行顺序错误
- 检查
dependsOn配置 - 使用
^task表示依赖任务 - 验证任务名称与 package.json 脚本匹配
问题: 开发服务器未启动
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true // 添加此项
}
}
}
性能问题
问题: 构建耗时过长
# 使用并发限制运行
turbo run build --concurrency=2
# 使用过滤器减少构建
turbo run build --filter='...[origin/main]'
# 检查不必要的依赖
turbo run build --dry-run
问题: 远程缓存无效
# 验证认证
turbo link
# 检查环境变量
echo $TURBO_TOKEN
echo $TURBO_TEAM
# 测试连接
turbo run build --output-logs=hash-only
迁移指南
从 Lerna
- 用 Turborepo 替换 Lerna:
npm uninstall lerna
npm install turbo --save-dev
- 将 lerna.json 转换为 turbo.json:
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
}
}
}
- 更新脚本:
{
"scripts": {
"build": "turbo run build",
"test": "turbo run test"
}
}
从 Nx
- 安装 Turborepo:
npm install turbo --save-dev
- 将 nx.json 转换为 turbo.json:
- 将 targetDefaults 映射到 pipeline
- 转换 dependsOn 语法
- 配置缓存
- 更新工作区配置
- 迁移 CI/CD 脚本
资源
- 文档: https://turbo.build/repo/docs
- 示例: https://github.com/vercel/turbo/tree/main/examples
- Discord: https://turbo.build/discord
- GitHub: https://github.com/vercel/turbo
实施清单
设置 Turborepo 时:
- [ ] 全局或按项目安装 Turborepo
- [ ] 设置工作区结构 (apps/, packages/)
- [ ] 创建 turbo.json 带管道配置
- [ ] 定义任务依赖 (build, test, lint)
- [ ] 为每个任务配置缓存输出
- [ ] 设置全局依赖和环境变量
- [ ] 链接到远程缓存 (Vercel 或自定义)
- [ ] 配置 CI/CD 集成
- [ ] 为大型存储库添加过滤策略
- [ ] 为团队记录 monorepo 结构
- [ ] 设置代码生成 (turbo gen)
- [ ] 配置带 turbo prune 的 Docker 构建
- [ ] 本地测试缓存行为
- [ ] 在 CI 中验证远程缓存
- [ ] 优化并发设置