包配置
许多 monorepo 可以在根目录中声明一个 turbo.json,其中包含适用于所有包的 任务描述。但是,有时 monorepo 可能包含需要以不同方式配置其任务的包。
为了适应这种情况,Turborepo 允许您在任何包中使用 turbo.json 扩展根配置。这种灵活性使更多样化的应用程序和包能够在工作空间中共存,并允许包所有者维护专门的任务和配置,而不会影响 monorepo 的其他应用程序和包。
工作原理
要覆盖根 turbo.json 中定义的任何任务的配置,请在 monorepo 的任何包中添加一个带有顶级 extends 键的 turbo.json 文件:
{
"extends": ["//"],
"tasks": {
"build": {
// 此包中构建任务的自定义配置
},
"special-task": {} // 此包特有的新任务
}
}
目前,extends 键的唯一有效值是 ["//"]。// 是用于标识 monorepo 根目录的特殊名称。
包中的配置可以覆盖 任务的任何配置。任何未包含的键都从扩展的 turbo.json 继承。
示例
一个工作空间中的不同框架
假设您的 monorepo 有多个 Next.js 应用程序和一个 SvelteKit 应用程序。两个框架都在各自的 package.json 中使用 build 脚本创建构建输出。您_可以_配置 Turborepo 在根目录使用单个 turbo.json 运行这些任务,如下所示:
{
"tasks": {
"build": {
"outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
}
}
}
请注意,即使 Next.js 应用程序不生成 .svelte-kit 目录,反之亦然,也需要将 .next/** 和 .svelte-kit/** 都指定为 outputs。
使用包配置,您可以在 apps/my-svelte-kit-app/turbo.json 中的 SvelteKit 包中添加自定义配置:
{
"extends": ["//"],
"tasks": {
"build": {
"outputs": [".svelte-kit/**"]
}
}
}
并从根配置中删除 SvelteKit 特定的 outputs:
{
"tasks": {
"build": {
- "outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
+ "outputs": [".next/**", "!.next/cache/**"]
}
}
}
这不仅使每个配置更易于阅读,还将配置放在更接近使用它的地方。
专门的任务
在另一个示例中,假设一个包中的 build 任务 dependsOn 一个 compile 任务。您可以将其普遍声明为 dependsOn: ["compile"]。这意味着您的根 turbo.json 必须有一个空的 compile 任务条目:
{
"tasks": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
使用包配置,您可以将该 compile 任务移动到 apps/my-custom-app/turbo.json 中:
{
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
并从根目录中删除它:
{
"tasks": {
+ "build": {}
- "build": {
- "dependsOn": ["compile"]
- },
- "compile": {}
}
}
现在,my-app 的所有者可以完全拥有他们的 build 任务,但继续继承在根目录定义的任何其他任务。
与包特定任务的比较
乍一看,包配置可能听起来很像根 turbo.json 中的 package#task 语法。这些功能相似,但有一个重要区别:当您在根 turbo.json 中声明包特定任务时,它_完全_覆盖基线任务配置。使用包配置,任务配置会被合并。
再次考虑具有多个 Next.js 应用程序和一个 Sveltekit 应用程序的 monorepo 示例。使用包特定任务,您可能会这样配置根 turbo.json:
{
"tasks": {
"build": {
"outputLogs": "hash-only",
"inputs": ["src/**"],
"outputs": [".next/**", "!.next/cache/**"]
},
"my-sveltekit-app#build": {
"outputLogs": "hash-only", // 必须重复这个
"inputs": ["src/**"], // 必须重复这个
"outputs": [".svelte-kit/**"]
}
}
}
在此示例中,my-sveltekit-app#build 完全覆盖了 Sveltekit 应用程序的 build,因此 outputLogs 和 inputs 也需要重复。
使用包配置,outputLogs 和 inputs 是继承的,因此您不需要重复它们。您只需要在 my-sveltekit-app 配置中覆盖 outputs。
虽然没有计划删除包特定任务配置,但我们期望包配置可以用于大多数用例。
边界标签 ::badge实验性
包配置也用于为边界声明标签。为此,请在您的 turbo.json 中添加 tags 字段:
{
+ "tags": ["my-tag"],
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
从那里,您可以定义标签可以拥有哪些依赖项或依赖者的规则。查看 边界文档 了解更多详细信息。
限制
虽然总体思路与根 turbo.json 相同,但包配置带有一组防护措施,可以防止包创建潜在的混乱情况。
包配置不能使用 the workspace#task 语法 作为任务条目
package 是根据配置的位置推断的,不可能更改另一个包的配置。例如,在 my-nextjs-app 的包配置中:
{
"tasks": {
"my-nextjs-app#build": {
// ❌ 这是不允许的。即使它引用了正确的包,
// "my-nextjs-app" 是推断的,我们不需要再次指定它。
// 这种语法也有不同的行为,所以我们不想允许它。
// (参见"与包特定任务的比较"部分)
},
"my-sveltekit-app#build": {
// ❌ 从 "my-nextjs-app" 的包配置中更改 "my-sveltekit-app" 包的配置是不允许的。
},
"build": {
// ✅ 只需使用任务名称!
}
}
}
请注意,build 任务仍然可以依赖于包特定任务:
{
"tasks": {
"build": {
"dependsOn": ["some-pkg#compile"] }
}
}
包配置只能覆盖 tasks 键中的值
在包配置中不可能覆盖 全局配置,如 globalEnv 或 globalDependencies。需要在包配置中更改的配置不是真正的全局配置,应该以不同的方式配置。
根 turbo.json 不能使用 extends 键
为了避免在包上创建循环依赖,根 turbo.json 不能从任何东西扩展。extends 键将被忽略。
故障排除
在大型 monorepo 中,有时很难理解 Turborepo 如何解释您的配置。为了帮助解决这个问题,我们在 Dry Run 输出中添加了 resolvedTaskDefinition。例如,如果您运行 turbo run build --dry-run,输出将包括在运行 build 任务之前考虑的所有 turbo.json 配置的组合。