配置任务
任务是 Turborepo 运行的脚本。你可以表达 turbo.json
configuration 和 软件包图表 中任务之间的关系。
¥A task is a script that Turborepo runs. You can express relationships between tasks in your turbo.json
configuration and Package Graph.
Turborepo 始终会并行执行所有工作,以确保一切尽可能快地运行。这比一次运行一个任务要快,这也是 Turborepo 如此快速的原因之一。
¥Turborepo will always parallelize any work that it can to ensure everything runs as fast as possible. This is faster than running tasks one at a time, and it's a part of what makes Turborepo so fast.
例如,yarn workspaces run lint && yarn workspaces run build && yarn workspaces run test
如下所示:
¥For example, yarn workspaces run lint && yarn workspaces run build && yarn workspaces run test
would look like this:


但是,为了使用 Turborepo 更快地完成相同的工作,你可以使用 turbo run lint build test
:
¥But, to get the same work done faster with Turborepo, you can use turbo run lint build test
:


入门
¥Getting started
根 turbo.json
文件是注册 Turborepo 将运行的任务的地方。定义好任务后,你就可以使用 turbo run
运行一个或多个任务。
¥The root turbo.json
file is where you'll register the tasks that Turborepo will run. Once you have your tasks defined, you'll be able to run one or more tasks using turbo run
.
-
如果你是新手,我们建议你使用 使用
create-turbo
创建新仓库 并编辑turbo.json
文件以尝试本指南中的代码片段。¥If you're starting fresh, we recommend creating a new repository using
create-turbo
and editing theturbo.json
file to try out the snippets in this guide. -
如果你要在现有存储库中采用 Turborepo,请在存储库的根目录中创建一个
turbo.json
文件。你将使用它来了解本指南中的其余配置选项。¥If you're adopting Turborepo in an existing repository, create a
turbo.json
file in the root of your repository. You'll be using it to learn about the rest of the configuration options in this guide.
定义任务
¥Defining tasks
tasks
对象中的每个键都是一个可由 turbo run
执行的任务。Turborepo 将在你的包中搜索其 package.json
中与任务同名的脚本。
¥Each key in the tasks
object is a task that can be executed by turbo run
. Turborepo will search your packages for scripts in their package.json
that have the same name as the task.
要定义任务,请在 turbo.json
中使用 tasks
对象。例如,一个名为 build
且没有依赖和输出的基本任务可能如下所示:
¥To define a task, use the tasks
object in turbo.json
. For example, a basic task with no dependencies and no outputs named build
might look like this:


如果你此时运行 turbo run build
,Turborepo 将并行运行你软件包中的所有 build
脚本,并且不会缓存任何文件输出。这将很快导致错误。你缺少一些重要的部分,无法使其按预期工作。
¥If you run turbo run build
at this point, Turborepo will run all build
scripts in your packages in parallel and won't cache any file outputs. This will quickly lead to errors. You're missing a few important pieces to make this work how you'd expect.
按正确顺序运行任务
¥Running tasks in the right order
dependsOn
键 用于指定在其他任务开始运行之前必须完成的任务。例如,在大多数情况下,你希望库的 build
脚本在应用的 build
脚本运行之前完成。为此,你需要使用以下 turbo.json
:
¥The dependsOn
key is used to specify the tasks that must complete before a different task begins running. For example, in most cases, you want the build
script for your libraries to complete before your application's build
script runs. To do this, you'd use the following turbo.json
:


现在,你已拥有预期的构建顺序,即先构建依赖,再构建依赖。
¥You now have the build order you would expect, building dependencies before dependents.
但要小心。目前,你尚未将构建输出标记为缓存。为此,请跳转到 指定输出 部分。
¥But be careful. At this point, you haven't marked the build outputs for caching. To do so, jump to the Specifying outputs section.
依赖于 ^
依赖中的任务
¥Depending on tasks in dependencies with ^
^
微语法告知 Turborepo 从依赖图的底部开始运行任务。如果你的应用依赖于名为 ui
的库,并且该库包含 build
任务,则 ui
中的 build
脚本将首先运行。成功完成后,应用中的 build
任务将运行。
¥The ^
microsyntax tells Turborepo to run the task starting at the bottom of the dependency graph. If your application depends on a library named ui
and the library has a build
task, the build
script in ui
will run first. Once it has successfully completed, the build
task in your application will run.
这是一个重要的模式,因为它可以确保应用的 build
任务拥有编译所需的所有必要依赖。当你的依赖图发展到具有多层任务依赖的更复杂结构时,此概念也适用。
¥This is an important pattern as it ensures that your application's build
task will have all of the necessary dependencies that it needs to compile. This concept also applies as your dependency graph grows to a more complex structure with many levels of task dependencies.
依赖于同一包中的任务
¥Depending on tasks in the same package
有时,你可能需要确保同一个软件包中的两个任务按特定顺序运行。例如,你可能需要先在库中运行 build
任务,然后再在同一个库中运行 test
任务。为此,请将 dependsOn
键中的脚本指定为纯字符串(不带 ^
)。
¥Sometimes, you may need to ensure that two tasks in the same package run in a specific order. For example, you may need to run a build
task in your library before running a test
task in the same library. To do this, specify the script in the dependsOn
key as a plain string (without the ^
).


依赖于特定包中的特定任务
¥Depending on a specific task in a specific package
你还可以指定特定包中要依赖的单个任务。在下面的示例中,utils
中的 build
任务必须在任何 lint
任务之前运行。
¥You can also specify an individual task in a specific package to depend on. In the example below, the build
task in utils
must be run before any lint
tasks.


你还可以更具体地指定依赖任务,将其限制在某个软件包上:
¥You can also be more specific about the dependent task, limiting it to a certain package:


使用此配置,你的 web
包中的 lint
任务只能在 utils
包中的 build
任务完成后运行。
¥With this configuration, the lint
task in your web
package can only be run after the build
task in the utils
package is complete.
无依赖
¥No dependencies
某些任务可能没有任何依赖。例如,用于在 Markdown 文件中查找拼写错误的任务可能不需要关心其他任务的状态。在这种情况下,你可以省略 dependsOn
键或提供一个空数组。
¥Some tasks may not have any dependencies. For example, a task for finding typos in Markdown files likely doesn't need to care about the status of your other tasks. In this case, you can omit the dependsOn
key or provide an empty array.


指定 outputs
¥Specifying outputs
Turborepo 会缓存任务的输出,这样你就不会重复执行相同的工作。我们将在 缓存指南 中深入讨论这一点,但首先请确保你的任务已正确配置。
¥Turborepo caches the outputs of your tasks so that you never do the same work twice. We'll discuss this in depth in the Caching guide, but let's make sure your tasks are properly configured first.
outputs
键告知 Turborepo 在任务成功完成后应缓存的文件和目录。如果没有定义此键,Turborepo 将不会缓存任何文件。后续运行时命中缓存不会恢复任何文件输出。
¥The outputs
key tells Turborepo files and directories it should cache when the task has successfully completed. Without this key defined, Turborepo will not cache any files. Hitting cache on subsequent runs will not restore any file outputs.
以下是一些常用工具的输出示例:
¥Below are a few examples of outputs for common tools:


Globs 是相对于包的,因此 dist/**
将分别处理每个包输出的 dist
。关于如何为 outputs
键构建通配符模式的更多信息,请参阅 通配符规范。
¥Globs are relative to the package, so dist/**
will handle the dist
that is outputted for each package, respectively. For more on building globbing patterns for the outputs
key, see the globbing specification.
指定 inputs
¥Specifying inputs
inputs
键用于指定要包含在 caching 任务哈希值中的文件。默认情况下,Turborepo 将包含包中所有由 Git 跟踪的文件。但是,你可以使用 inputs
键更具体地指定哈希中包含哪些文件。
¥The inputs
key is used to specify the files that you want to include in the task's hash for caching. By default, Turborepo will include all files in the package that are tracked by Git. However, you can be more specific about which files are included in the hash using the inputs
key.
例如,一个用于查找 Markdown 文件中拼写错误的任务可以这样定义:
¥As an example, a task for finding typos in Markdown files could be defined like this:


现在,只有 Markdown 文件中的更改才会导致 spell-check
任务丢失缓存。
¥Now, only changes in Markdown files will cause the spell-check
task to miss cache.
此功能会退出 Turborepo 的所有默认 inputs
行为,包括跟随源代码管理跟踪的更改。这意味着你的 .gitignore
文件将不再被遵守,你需要确保不要用 glob 捕获这些文件。
¥This feature opts out of all of Turborepo's default inputs
behavior, including following along with changes tracked by source control. This means that your .gitignore
file will no longer be respected, and you will need to ensure that you do not capture those files with your globs.
要恢复默认行为,请使用 $TURBO_DEFAULT$
微语法。
¥To restore the default behavior, use the $TURBO_DEFAULT$
microsyntax.
使用 $TURBO_DEFAULT$
恢复默认设置
¥Restoring defaults with $TURBO_DEFAULT$
inputs
的默认行为 通常是你执行任务时所需要的。但是,你可以通过微调 inputs
键来忽略已知不会影响任务输出的文件更改,从而提高某些任务的缓存命中率。
¥The default inputs
behavior is often what you will want for your tasks. However, you can increase your cache hit ratios for certain tasks by fine-tuning your inputs
to ignore changes to files that are known to not affect the task's output.
因此,你可以使用 $TURBO_DEFAULT$
微语法来微调默认的 inputs
行为:
¥For this reason, you can use the $TURBO_DEFAULT$
microsyntax to fine-tune the default inputs
behavior:


在此任务定义中,Turborepo 将对 build
任务使用默认的 inputs
行为,但会忽略对 README.md
文件的更改。如果 README.md
文件发生更改,任务仍会命中缓存。
¥In this task definition, Turborepo will use the default inputs
behavior for the build
task, but will ignore changes to the README.md
file. If the README.md
file is changed, the task will still hit cache.
注册根任务
¥Registering Root Tasks
你还可以使用 turbo
在工作区根目录下的 package.json
中运行脚本。例如,除了每个包中的 lint
任务之外,你可能还想为工作区根目录中的文件运行 lint:root
任务:
¥You can also run scripts in the package.json
in the Workspace root using turbo
. For example, you may want to run a lint:root
task for the files in your Workspace's root directory in addition to the lint
task in each package:


根任务现已注册,turbo run lint:root
现在将运行该任务。你还可以运行 turbo run lint lint:root
来运行所有 linting 任务。
¥With the Root Task now registered, turbo run lint:root
will now run the task. You can also run turbo run lint lint:root
to run all your linting tasks.
何时使用 Root Tasks
¥When to use Root Tasks
-
工作区根目录的 Linting 和格式化:你的工作区根目录中可能有需要进行 lint 和格式化的代码。例如,你可能想在根目录中运行 ESLint 或 Prettier。
¥Linting and formatting of the Workspace root: You might have code in your Workspace root that you want to lint and format. For example, you might want to run ESLint or Prettier in your root directory.
-
增量迁移:在迁移到 Turborepo 时,你可能有一个中间步骤,其中有一些脚本尚未移动到包中。在这种情况下,你可以创建一个根任务来开始迁移,并稍后将任务分散到各个包。
¥Incremental migration: While you're migrating to Turborepo, you might have an in-between step where you have some scripts that you haven't moved to packages yet. In this case, you can create a Root Task to start migrating and fan the tasks out to packages later.
-
不属于包范围的脚本:你可能有一些脚本在特定包的上下文中没有意义。这些脚本可以注册为根任务,因此你仍然可以使用
turbo
运行它们,以实现缓存、并行化和工作流目的。¥Scripts without a package scope: You may have some scripts that don't make sense in the context of specific packages. Those scripts can be registered as Root Tasks so you can still run them with
turbo
for caching, parallelization, and workflow purposes.
高级用例
¥Advanced use cases
使用软件包配置
¥Using Package Configurations
软件包配置 是直接放置在包中的 turbo.json
文件。这允许包为其自身任务定义特定行为,而不会影响仓库的其余部分。
¥Package Configurations are turbo.json
files that are placed directly into a package. This allows a package to define specific behavior for its own tasks without affecting the rest of the repository.
在拥有多个团队的大型单体仓库中,这可以让团队更好地控制自己的任务。要了解更多信息,请访问 包配置文档
¥In large monorepos with many teams, this allows teams greater control over their own tasks. To learn more, visit the Package Configurations documentation
具有运行时依赖的长时间运行任务
¥Long-running tasks with runtime dependencies
你可能有一个长时间运行的任务,需要另一个任务始终同时运行。为此,请使用 with
键。
¥You might have a long-running task that requires another task to always be running at the same time. For this, use the with
key.


长时间运行的任务永远不会退出,这意味着你不能依赖它。相反,每当 web#dev
任务运行时,with
关键字都会运行 api#dev
任务。
¥A long-running task never exits, meaning you can't depend on it. Instead, the with
keyword will run the api#dev
task whenever the web#dev
task runs.
执行副作用
¥Performing side-effects
某些任务无论如何都应该始终运行,例如缓存构建后的部署脚本。对于这些任务,请将 "cache": false
添加到你的任务定义中。
¥Some tasks should always be run no matter what, like a deployment script after a cached build. For these tasks, add "cache": false
to your task definition.


可并行运行的依赖任务
¥Dependent tasks that can be run in parallel
某些任务可以并行运行,尽管它们依赖于其他软件包。符合此描述的任务示例是 Linter,因为 Linter 不需要等待依赖中的输出即可成功运行。
¥Some tasks can be run in parallel despite being dependent on other packages. An example of tasks that fit this description are linters, since a linter doesn't need to wait for outputs in dependencies to run successfully.
因此,你可能倾向于像这样定义你的 check-types
任务:
¥Because of this, you may be tempted to define your check-types
task like this:


这会并行运行你的任务 - 但它不考虑依赖中的源代码更改。这意味着你可以:
¥This runs your tasks in parallel - but doesn't account for source code changes in dependencies. This means you can:
-
对你的
ui
软件包的界面进行重大更改。¥Make a breaking change to the interface of your
ui
package. -
运行
turbo check-types
,在依赖于ui
的应用包中命中缓存。¥Run
turbo check-types
, hitting cache in an application package that depends onui
.
这是不正确的,因为尽管应用包未更新以使用新接口,但它仍会显示成功的缓存命中。在编辑器中手动检查应用包中的 TypeScript 错误可能会发现错误。
¥This is incorrect, since the application package will show a successful cache hit, despite not being updated to use the new interface. Checking for TypeScript errors in your application package manually in your editor is likely to reveal errors.
因此,你需要对 check-types
任务定义进行一些小改动:
¥Because of this, you make a small change to your check-types
task definition:


如果你再次测试在 ui
软件包中进行重大更改,你会注意到缓存行为现在是正确的。但是,任务不再并行运行。
¥If you test out making breaking changes in your ui
package again, you'll notice that the caching behavior is now correct. However, tasks are no longer running in parallel.
为了同时满足这两个要求(正确性和并行性),你可以将 传输节点 引入到你的任务图中:
¥To meet both requirements (correctness and parallelism), you can introduce Transit Nodes to your Task Graph:


这些 Transit 节点使用一个不执行任何操作的任务在包依赖之间建立关系,因为它与任何 package.json
中的脚本都不匹配。因此,你的任务可以并行运行,并能够感知其内部依赖的变化。
¥These Transit Nodes create a relationship between your package dependencies using a task that doesn't do anything because it doesn't match a script in any package.json
s. Because of this, your tasks can run in parallel and be aware of changes to their internal dependencies.
在此示例中,我们使用了名称 transit
- 但你可以将任务命名为工作区中尚未包含脚本的任何名称。
¥In this example, we used the name transit
- but you can name the task
anything that isn't already a script in your Workspace.
后续步骤
¥Next steps
配置 turbo.json
文档 中还有更多选项,你将在接下来的指南中探索。现在,你可以开始运行一些任务来了解基本工作原理。
¥There are more options available in the Configuring turbo.json
documentation that you will explore in the coming guides. For now, you can start running a few tasks to see how the basics work.