Turborepo logo

包配置

许多 Monorepo 可以在根目录下声明一个 turbo.json 文件,其中包含应用于所有包的任务描述。但是,有时,一个 Monorepo 可能包含需要以不同方式配置其任务的包。

为了适应这种情况,Turborepo 允许你在任何包中使用 turbo.json 扩展根配置。这种灵活性使更多样化的应用和包能够共存于一个 Workspace 中,并允许包所有者维护专门的任务和配置,而不会影响 Monorepo 的其他应用和包。

工作原理

要覆盖根 turbo.json 中定义的任何任务的配置,请在 Monorepo 的任何包中添加一个 turbo.json 文件,并包含顶级的 extends

./apps/my-app/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": {
      // Custom configuration for the build task in this package
    },
    "special-task": {} // New task specific to this package
  }
}

目前,extends 键的唯一有效值是 ["//"]// 是一个用于标识 Monorepo 根目录的特殊名称。

包中的配置可以覆盖任务的任何配置。任何未包含的键都将从扩展的 turbo.json 中继承。

示例

同一 Workspace 中的不同框架

假设你的 Monorepo 有多个 Next.js 应用和一个 SvelteKit 应用。这两个框架都使用各自 package.json 中的 build 脚本创建构建输出。你可以配置 Turborepo 以使用根目录下的单个 turbo.json 文件运行这些任务,如下所示

./turbo.json
{
  "tasks": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
    }
  }
}

请注意,即使 Next.js 应用不生成 .svelte-kit 目录,反之亦然,也需要将 .next/**.svelte-kit/** 都指定为 outputs

使用包配置,你可以改为在 SvelteKit 包的 apps/my-svelte-kit-app/turbo.json 中添加自定义配置

./apps/my-svelte-kit-app/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": {
      "outputs": [".svelte-kit/**"]
    }
  }
}

并从根配置中删除 SvelteKit 特有的 outputs

./turbo.json
{
  "tasks": {
    "build": {
-      "outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
+      "outputs": [".next/**", "!.next/cache/**"]
    }
  }
}

这不仅使每个配置更易于阅读,而且使配置更接近其使用位置。

专门的任务

在另一个示例中,假设一个包中的 build 任务 dependsOn 一个 compile 任务。你可以将其通用地声明为 dependsOn: ["compile"]。这意味着你的根 turbo.json 必须有一个空的 compile 任务条目

./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["compile"]
    },
    "compile": {}
  }
}

使用包配置,你可以将 compile 任务移动到 apps/my-custom-app/turbo.json 中,

./apps/my-app/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": {
      "dependsOn": ["compile"]
    },
    "compile": {}
  }
}

并从根目录中删除它

./turbo.json
{
  "tasks": {
+    "build": {}
-    "build": {
-      "dependsOn": ["compile"]
-    },
-    "compile": {}
  }
}

现在,my-app 的所有者可以完全拥有他们的 build 任务,但继续继承根目录下定义的任何其他任务。

与包特定任务的比较

乍一看,包配置可能听起来很像根 turbo.json 中的 package#task 语法。这些功能类似,但有一个显着的区别:当你在根 turbo.json 中声明一个包特定任务时,它会完全覆盖基线任务配置。使用包配置,任务配置是合并的。

再次考虑具有多个 Next.js 应用和一个 Sveltekit 应用的 Monorepo 示例。使用包特定任务,你可能会像这样配置你的根 turbo.json

./turbo.json
{
  "tasks": {
    "build": {
      "outputLogs": "hash-only",
      "inputs": ["src/**"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "my-sveltekit-app#build": {
      "outputLogs": "hash-only", // must duplicate this
      "inputs": ["src/**"], // must duplicate this
      "outputs": [".svelte-kit/**"]
    }
  }
}

在此示例中,my-sveltekit-app#build 完全覆盖了 Sveltekit 应用的 build,因此 outputLogsinputs 也需要重复。

使用包配置,outputLogsinputs 是继承的,因此你无需重复它们。你只需要在 my-sveltekit-app 配置中覆盖 outputs

尽管目前没有计划删除包特定任务配置,但我们预计包配置可以在大多数用例中替代使用。

边界标签 实验性

包配置也用于声明边界的标签。为此,请在你的 turbo.json 中添加 tags 字段

./apps/my-app/turbo.json
{
+ "tags": ["my-tag"],
  "extends": ["//"],
  "tasks": {
    "build": {
      "dependsOn": ["compile"]
    },
    "compile": {}
  }
}

从那里,你可以定义标签可以具有哪些依赖项或被依赖项的规则。查看 边界文档 了解更多详情。

局限性

虽然总体思路与根 turbo.json 相同,但包配置带有一组防护措施,可以防止包创建潜在的混淆情况。

包配置不能使用workspace#task 语法作为任务条目

package 是根据配置的位置推断出来的,并且不可能更改另一个包的配置。例如,在 my-nextjs-app 的包配置中

./apps/my-nextjs-app/turbo.json
{
  "tasks": {
    "my-nextjs-app#build": {
      // ❌ This is not allowed. Even though it's
      // referencing the correct package, "my-nextjs-app"
      // is inferred, and we don't need to specify it again.
      // This syntax also has different behavior, so we do not want to allow it.
      // (see "Comparison to package-specific tasks" section)
    },
    "my-sveltekit-app#build": {
      // ❌ Changing configuration for the "my-sveltekit-app" package
      // from Package Configuration in "my-nextjs-app" is not allowed.
    },
    "build": {
      // ✅ just use the task name!
    }
  }
}

请注意,build 任务仍然可以依赖于包特定任务

./apps/my-nextjs-app/turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["some-pkg#compile"] 
    }
  }
}

包配置只能覆盖 tasks 键中的值

无法在包配置中覆盖 全局配置,例如 globalEnvglobalDependencies。需要在包配置中更改的配置不是真正的全局配置,应该以不同的方式配置。

根 turbo.json 不能使用 extends

为了避免在包上创建循环依赖,根 turbo.json 不能从任何内容扩展。extends 键将被忽略。

故障排除

在大型 Monorepo 中,有时可能难以理解 Turborepo 如何解释你的配置。为了帮助你,我们在 Dry Run 输出中添加了 resolvedTaskDefinition。例如,如果你运行 turbo run build --dry-run,输出将包括在运行 build 任务之前考虑的所有 turbo.json 配置的组合。