Turborepo

5 阅读2分钟

简介

Turborepo = 给 monorepo 用的“智能任务调度器 + 缓存引擎”

为什么会需要 Turborepo

传统 monorepo 的痛点,假设你有如下目录:

packages/
  utils
  ui
apps/
  admin
  docs

依赖关系:

admin -> ui -> utils
docs  -> ui

没 turbo 时,常见做法

pnpm -r dev
pnpm -r build

问题来了:

  1. ❌ 不关心依赖顺序,执行 builddev 命令执行顺序不保证符合包依赖顺序,过去的解决方式"build": "pnpm --filter utils build && pnpm --filter ui build && pnpm --filter admin build"
  2. ❌ 改一个 utils,全部 app 都 build
  3. ❌ 每次 CI 都从 0 开始
  4. ❌ 项目一大,命令慢到崩溃

Turborepo 到底解决了什么

  1. 按依赖图调度任务(核心能力)
    Turborepo 会分析:package.json 里的依赖关系、workspace 结构,然后自动得到一张图:
utils
  ↓
 ui
  ↓
admin / docs

执行turbo run build后:

  • 先 build utils
  • 再 build ui
  • 最后 build admin / docs
  • 能并行的并行,不能的就等
  • 不用你手动维护顺序

缓存机制

当你跑过一次turbo run build 下次:

  • 源码没变
  • 依赖没变
  • 输出目录没变

👉 直接跳过,秒完成

CI / 团队缓存(进阶)

  • A 同事 build 过
  • B 同事拉代码再 build,直接命中缓存

只跑“受影响”的包

你只改了 packages/utils 时,再执行 turbo run build 结果是:

  • ✅ utils
  • ✅ ui(依赖 utils)
  • ✅ admin / docs
  • ❌ 其他无关包不会跑

pnpm -r:全部跑
turbo:最小集合

dev 场景

它会:

  • 启动所有有 dev 脚本的包
  • 按依赖顺序
  • 并行拉起
  • 支持长期运行(vite dev server)

Turborepo 使用

  • 安装 turbo
pnpm add -D turbo
  • 新增 turbo.json
{
  // 给编辑器 / IDE 用的,提供智能提示、校验,不影响运行
  "$schema": "https://turbo.build/schema.json",
  // 这些文件一旦改动,整个 turbo 缓存全部失效
  "globalDependencies": [
    // 依赖变了,构建产物一定可能变,必须让缓存失效
    "pnpm-lock.yaml",
    // 本地环境变量,会影响 dev / build 行为,防止你“改了环境却命中旧缓存”
    "**/.env.*local",
    // 编译目标,path alias,strict 规则,改一次,所有包都该重跑
    "**/tsconfig*.json",
    "internal/node-utils/*.json",
    "internal/node-utils/src/**/*.ts",
    // Tailwind 主题
    "internal/tailwind-config/src/**/*.ts",
    // Vite 通用配置
    "internal/vite-config/*.json",
    "internal/vite-config/src/**/*.ts",
    "scripts/*/src/**/*.ts",
    "scripts/*/src/**/*.json"
  ],
  // NODE_ENV 变化 → 所有任务缓存失效,防止你用 dev 的缓存跑 prod 构建
  "globalEnv": ["NODE_ENV"],
  // 调度规则
  "tasks": {
    "build": {
      // 所有依赖包先 build
      "dependsOn": ["^build"],
      // 构建产物,turbo 用它们来:判断是否可缓存、判断是否命中缓存
      "outputs": [
        // 普通前端:`dist/**`
        "dist/**",
        // 打包产物:`dist.zip`
        "dist.zip",
        // 文档站:`.vitepress/dist`
        ".vitepress/dist.zip",
        ".vitepress/dist/**"
      ]
    },
    "preview": {
      // preview 必须在 build 之后
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "build:analyze": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "@vben/backend-mock#build": {
      "dependsOn": ["^build"],
      "outputs": [".nitro/**", ".output/**"]
    },
    "test:e2e": {},
    "dev": {
      // 不依赖 build(dev 自己处理)
      "dependsOn": [],
      "outputs": [],
     // 不缓存(dev server 没意义)
      "cache": false,
      // vite / node server 不会被当成“已完成”
      "persistent": true
    },
    "typecheck": {
      "outputs": []
    }
  }
}