路径 A:create-turbo 模板
pnpm dlx create-turbo@latest my-turborepo # 交互式选: # - Package manager: pnpm(推荐) # - Template: default / kitchen sink / 其它 cd my-turborepo pnpm install
生成的目录:
my-turborepo/
├── turbo.json ← Turbo 配置
├── pnpm-workspace.yaml
├── package.json ← 根
├── apps/
│ ├── web/ ← Next.js 应用
│ └── docs/ ← Next.js 文档
└── packages/
├── ui/ ← 共享组件库
├── eslint-config/
└── typescript-config/
路径 B:接入已有 pnpm workspace
pnpm add -Dw turbo
根 package.json:
{
"name": "my-mono",
"private": true,
"packageManager": "pnpm@9.12.0",
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test"
},
"devDependencies": {
"turbo": "^2.2.3"
}
}
最小 turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
tasks 的三个关键字段
dependsOn:这个任务需要先跑完哪些outputs:任务的产物路径,用来缓存cache:默认 true;dev 这种长任务必须 false
^ 前缀的含义
"build": { "dependsOn": ["^build"] }
^build:依赖的 workspace 包先跑 build(跨包)build:同一个 workspace 内的 build"test", "^build":自己的 test 前置要求所有依赖先 build
子包 package.json
// packages/ui/package.json { "name": "@myorg/ui", "version": "0.0.1", "main": "./dist/index.js", "scripts": { "build": "tsc", "lint": "eslint src", "test": "vitest run" } }
Turbo 不自己跑编译——它调用每个包 package.json 里定义的 script。这意味着任何已有的 npm scripts 可以直接接入。
第一次跑
pnpm turbo run build
• Packages in scope: @myorg/docs, @myorg/ui, @myorg/web • Running build in 3 packages • Remote caching disabled @myorg/ui:build: cache miss, executing 5a2f1e8c... @myorg/ui:build: $ tsc @myorg/ui:build: done in 3.2s @myorg/web:build: cache miss, executing 7b4d8c3f... @myorg/web:build: $ next build @myorg/web:build: done in 18.5s @myorg/docs:build: cache miss, executing a12b34cd... @myorg/docs:build: $ next build @myorg/docs:build: done in 14.2s Tasks: 3 successful, 3 total Cached: 0 cached, 3 total Time: 22.1s
第二次跑(魔法时刻)
pnpm turbo run build
@myorg/ui:build: cache hit, replaying logs 5a2f1e8c... @myorg/web:build: cache hit, replaying logs 7b4d8c3f... @myorg/docs:build: cache hit, replaying logs a12b34cd... Tasks: 3 successful, 3 total Cached: 3 cached, 3 total Time: 350ms >>> FULL TURBO
22 秒 → 350 毫秒,FULL TURBO 横幅出现——所有任务都命中缓存。Turbo 直接把上次的 dist/.next 恢复,根本不跑 tsc/next build。
什么决定 hash?
默认包括:包源码文件 + package.json + dependency 包的 hash + 相关的环境变量 + 依赖包的 lockfile。任一变化 → hash 变 → 缓存不命中 → 重跑。
默认包括:包源码文件 + package.json + dependency 包的 hash + 相关的环境变量 + 依赖包的 lockfile。任一变化 → hash 变 → 缓存不命中 → 重跑。
给任务传参
pnpm turbo run test -- --coverage # -- 之后的参数传给 vitest pnpm turbo run build --filter=@myorg/web # 只 build web pnpm turbo run build --concurrency=1 # 串行(默认并行) pnpm turbo run build --force # 忽略缓存,强制重跑
看任务图
pnpm turbo run build --graph # 输出 DOT 文件 pnpm turbo run build --graph=graph.png # 生成 PNG(需要 graphviz) pnpm turbo run build --dry-run # 不执行,只显示会跑什么 pnpm turbo run build --dry-run=json # JSON 输出,便于脚本处理
.turbo 目录
my-turborepo/ ├── .turbo/ ← 根的日志和元数据 │ ├── cookies/ │ ├── daemon/ │ └── runs/ ├── apps/web/.turbo/ ← 每包各自的 cache │ ├── cache/ ← 缓存产物 │ │ └── 5a2f1e8c.tar.zst │ └── turbo-build.log ← 任务日志 └── node_modules/.cache/turbo/ ← 本地 cache 的另一位置
echo ".turbo" >> .gitignore # .turbo 不该进 git
globalDependencies
{
"globalDependencies": [
".env",
".env.*",
"tsconfig.json"
],
"tasks": { ... }
}
全仓 hash 依赖——这些文件改了 → 所有任务缓存失效。.env、根 tsconfig 都是典型例子。
Node/pnpm 版本约束
{
"engines": {
"node": ">=18.17.0",
"pnpm": ">=9.0.0"
},
"packageManager": "pnpm@9.12.0"
}
.npmrc 配合
enable-pre-post-scripts=true auto-install-peers=true
确保 pre/post 脚本被 Turbo 能正确触发。
常见启动问题
could not find turbo.json
文件要在仓库根目录,和 pnpm-workspace.yaml 同级。
task "build" not found in pipeline
某个子包 package.json 没 build script,Turbo 也要求顶层 turbo.json 里有定义。
FULL TURBO 出不来
每次 hash 都变——常因
outputs 写漏(没把实际产物全列上)或任务非确定性(比如往 dist 写时间戳)。缓存太大
用
! 排除不需要缓存的子目录,如 ".next/**", "!.next/cache/**"。下一步
已经有最小可跑的 Turbo。下一章深入任务图:dependsOn 语法、^/$、交叉引用、全局依赖——把 CI 的拓扑搞对,缓存才稳定。
本章小结
pnpm dlx create-turbo@latest一键起新项目,或pnpm add -Dw turbo接入老项目- turbo.json 定义任务:
dependsOn+outputs+cache三要素 ^build表示依赖包的 build,build表示自己的- 第二次跑看到 FULL TURBO 表示缓存跑通
.turbo/目录加 .gitignore;globalDependencies列全仓级别的 hash 依赖