配置任务
Turborepo 将始终按照您的 turbo.json
配置和 包图 中描述的顺序运行任务,并在可能的情况下并行化工作,以确保一切都尽可能快地运行。这比一次运行一个任务更快,这也是 Turborepo 如此快速的原因之一。
例如,yarn workspaces run lint && yarn workspaces run test && yarn workspaces run build
将如下所示
但是,为了使用 Turborepo 更快地完成相同的工作,您可以使用 turbo run lint test build
入门
根 turbo.json
文件是您注册 Turborepo 将运行的任务的地方。定义任务后,您可以使用 turbo run
运行一个或多个任务。
- 如果您是全新开始,我们建议使用
create-turbo
创建新的存储库并编辑turbo.json
文件以尝试本指南中的代码片段。 - 如果您要在现有存储库中采用 Turborepo,请在存储库的根目录中创建一个
turbo.json
文件。您将使用它来了解本指南中其余的配置选项。
定义任务
tasks
对象中的每个键都是一个可以通过 turbo run
执行的任务。Turborepo 将在您的包中搜索与其任务名称相同的 package.json
中的脚本。
要定义任务,请使用 turbo.json
中的 tasks
对象。例如,一个没有依赖项且没有输出的名为 build
的基本任务可能如下所示
如果您此时运行 turbo run build
,Turborepo 将并行运行您包中的所有 build
脚本,并且不会缓存任何文件输出。这将很快导致错误。 您缺少一些重要的部分才能使其按预期工作。
按正确的顺序运行任务
dependsOn
键用于指定在开始运行其他任务之前必须完成的任务。例如,在大多数情况下,您希望库的 build
脚本在应用程序的 build
脚本运行之前完成。为此,您可以使用以下 turbo.json
您现在拥有您期望的构建顺序,在构建依赖项之前构建依赖者。
但请注意。 此时,您尚未标记构建输出以进行缓存。要执行此操作,请跳转到 指定输出 部分。
依赖具有 ^
的依赖项中的任务
^
微语法告诉 Turborepo 从依赖关系图的底部开始运行任务。如果您的应用程序依赖于名为 ui
的库,并且该库具有 build
任务,则 ui
中的 build
脚本将首先运行。成功完成后,您的应用程序中的 build
任务将运行。
这是一个重要的模式,因为它确保您的应用程序的 build
任务将拥有编译所需的所有必要依赖项。当您的依赖关系图增长到具有多个任务依赖级别时,此概念也适用。
依赖同一包中的任务
有时,您可能需要确保同一包中的两个任务以特定顺序运行。例如,您可能需要在库中运行 build
任务,然后在同一库中运行 test
任务。为此,请在 dependsOn
键中将脚本指定为纯字符串(不带 ^
)。
依赖于特定包中的特定任务
您还可以指定要依赖的特定包中的单个任务。在下面的示例中,必须先运行 utils
中的 build
任务,然后才能运行任何 lint
任务。
您还可以更具体地了解依赖任务,将其限制为特定包
使用此配置,只有在 utils
包中的 build
任务完成后,才能运行 web
包中的 lint
任务。
没有依赖项
某些任务可能没有任何依赖项。例如,用于在 Markdown 文件中查找拼写错误的任务可能不需要关心其他任务的状态。在这种情况下,您可以省略 dependsOn
键或提供一个空数组。
指定 outputs
Turborepo 会缓存您任务的输出,以便您永远不会重复执行相同的工作。我们将在缓存指南中深入讨论此内容,但让我们首先确保您的任务已正确配置。
outputs
键告诉 Turborepo 文件和目录,它应该在任务成功完成后缓存。如果没有定义此键,Turborepo 将不会缓存任何文件。在后续运行中命中缓存将不会恢复任何文件输出。
以下是一些常见工具的输出示例
Glob 相对于包,因此 dist/**
将分别处理每个包输出的 dist
。有关为 outputs
键构建 glob 模式的更多信息,请参见 glob 规范。
指定 inputs
inputs
键用于指定您要包含在任务哈希中的文件以进行缓存。默认情况下,Turborepo 将包含包中 Git 跟踪的所有文件。但是,您可以使用 inputs
键更具体地了解哈希中包含哪些文件。
例如,用于在 Markdown 文件中查找拼写错误的任务可以定义如下
现在,只有 Markdown 文件中的更改才会导致 spell-check
任务错过缓存。
此功能会选择退出 Turborepo 的所有默认 inputs
行为,包括跟踪源代码控制跟踪的更改。这意味着您的 .gitignore
文件将不再被遵循,您需要确保不要使用 glob 捕获这些文件。
要恢复默认行为,请使用 $TURBO_DEFAULT$
微语法。
使用 $TURBO_DEFAULT$
恢复默认值
默认的 inputs
行为通常是您希望任务执行的行为。但是,您可以通过微调 inputs
以忽略对已知不影响任务输出的文件的更改来提高某些任务的缓存命中率。
因此,您可以使用 $TURBO_DEFAULT$
微语法来微调默认的 inputs
行为
在此任务定义中,Turborepo 将对 build
任务使用默认的 inputs
行为,但会忽略对 README.md
文件的更改。如果 README.md
文件已更改,则该任务仍将命中缓存。
注册根任务
您还可以使用 turbo
在工作区根目录中的 package.json
中运行脚本。例如,您可能希望除了每个包中的 lint
任务之外,还为工作区根目录中的文件运行 lint:root
任务
现在注册了根任务,turbo run lint:root
现在将运行该任务。您还可以运行 turbo run lint lint:root
来运行所有 linting 任务。
何时使用根任务
- 工作区根目录的 Linting 和格式化:您可能在工作区根目录中有代码要进行 lint 和格式化。例如,您可能希望在根目录中运行 ESLint 或 Prettier。
- 增量迁移:在您迁移到 Turborepo 时,您可能会有一个中间步骤,其中有一些尚未移动到包的脚本。在这种情况下,您可以创建一个根任务来开始迁移,并在以后将任务分发到包中。
- 没有包范围的脚本:您可能有一些在特定包的上下文中没有意义的脚本。可以将这些脚本注册为根任务,以便您仍然可以使用
turbo
运行它们,以进行缓存、并行化和工作流目的。
高级用例
使用包配置
包配置是直接放置到包中的 turbo.json
文件。这允许包定义其自身任务的特定行为,而不会影响存储库的其余部分。
在具有许多团队的大型 monorepo 中,这使团队可以更好地控制自己的任务。要了解更多信息,请访问 包配置文档
执行副作用
某些任务应始终运行,无论如何,例如缓存构建后的部署脚本。对于这些任务,请将 "cache": false
添加到您的任务定义中。
可以并行运行的依赖任务
某些任务可以并行运行,即使它们依赖于其他包。适合此描述的任务示例是 linters,因为 linter 不需要等待依赖项中的输出才能成功运行。
因此,您可能会想将 check-types
任务定义如下
这将并行运行您的任务,但不会考虑依赖项中的源代码更改。这意味着您可以
- 对
ui
包的接口进行重大更改。 - 运行
turbo check-types
,在依赖于ui
的应用程序包中命中缓存。
这是不正确的,因为应用程序包会显示成功命中缓存,尽管它尚未更新以使用新的接口。在编辑器中手动检查应用程序包中的 TypeScript 错误可能会发现错误。
因此,您需要对 check-types
任务定义进行一个小更改。
如果您再次尝试在 ui
包中进行破坏性更改,您会注意到缓存行为现在是正确的。但是,任务不再并行运行。
为了满足这两个要求(正确性和并行性),您可以将 Transit 节点 引入到您的任务图中。
这些 Transit 节点使用一个不执行任何操作的任务(因为它与任何 package.json
中的脚本都不匹配)来创建包依赖项之间的关系。因此,您的任务可以并行运行并且感知到其内部依赖项的更改。
在这个例子中,我们使用了名称 transit
- 但您可以将该任务命名为工作区中尚未存在的任何脚本名称。
下一步
在 配置 turbo.json
文档 中有更多选项,您将在接下来的指南中进行探索。现在,您可以开始运行一些任务,以了解基本原理是如何工作的。
这有帮助吗?