软件包和任务图表

软件包图表

¥Package Graph

包图是包管理器创建的 monorepo 的结构。当你将 内部软件包 安装到其他依赖中时,Turborepo 将自动识别这些依赖,以建立对工作区 (Workspace) 的基础理解。

¥The Package Graph is the structure of your monorepo created by your package manager. When you install Internal Packages into each other, Turborepo will automatically identify those dependency relationships to build a foundational understanding of your Workspace.

这为任务图奠定了基础,你将在其中定义任务之间的关系。

¥This sets the groundwork for the Task Graph, where you'll define how tasks relate to each other.

任务图

¥Task Graph

turbo.json 中,你可以表达任务之间的关系。你可以将这些关系视为任务之间的依赖,但我们对它们有一个更正式的名称:任务图。

¥In turbo.json, you express how tasks relate to each other. You can think of these relationships as dependencies between tasks, but we have a more formal name for them: the Task Graph.

Good to know: 

你可以使用 --graph 标志 为你的任务生成可视化的任务图。

¥You can generate a visualization of the task graph for your tasks using the --graph flag.

Turborepo 使用一种称为 有向无环图 (DAG) 的数据结构来理解你的仓库及其任务。图表由 "nodes" 和 "edges" 组成。在任务图中,节点代表任务,边代表任务之间的依赖。有向图表示连接每个节点的边具有方向,因此如果任务 A 指向任务 B,我们可以说任务 A 依赖于任务 B。边缘的方向取决于哪个任务依赖于哪个任务。

¥Turborepo uses a data structure called a directed acyclic graph (DAG) to understand your repository and its tasks. A graph is made up of "nodes" and "edges". In the Task Graph, the nodes are tasks and the edges are the dependencies between tasks. A directed graph indicates that the edges connecting each node have a direction, so if Task A points to Task B, we can say that Task A depends on Task B. The direction of the edge depends on which task depends on which.

例如,假设你有一个 monorepo,其中包含 ./apps/web 中的应用,该应用依赖于两个包:@repo/ui@repo/utils

¥For example, let's say you have a monorepo with an application in ./apps/web that depends on two packages: @repo/ui and @repo/utils:

你还有一个依赖于 ^buildbuild 任务:

¥You also have a build task that depends on ^build:

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}

Turborepo 将构建如下任务图:

¥Turborepo will build a task graph like this:

Task graph visualization. The diagram has one node at the top named "apps/web" with two lines that connect to other nodes, "packages/ui" and "packages/utils" respectively.

传输节点

¥Transit Nodes

构建任务图时的一个挑战是处理嵌套依赖。例如,假设你的 monorepo 中有一个 docs 应用,它依赖于 ui 包,而 ui 包又依赖于 core 包:

¥A challenge when building a Task Graph is handling nested dependencies. For example, let's say your monorepo has a docs app that depends on the ui package, which depends on the core package:

假设 docs 应用和 core 软件包各自包含一个 build 任务,但 ui 软件包没有。你还有一个 turbo.json,它以与上述 "dependsOn": ["^build"] 相同的方式配置 build 任务。运行 turbo run build 时,你期望发生什么?

¥Let's assume the docs app and the core package each have a build task, but the ui package does not. You also have a turbo.json that configures the build task the same way as above with "dependsOn": ["^build"]. When you run turbo run build, what would you expect to happen?

Turborepo 将构建以下任务图:

¥Turborepo will build this Task Graph:

A Task Graph visualization with a Transit Node. The diagram has one node at the top named "apps/doc" with a line that connects to a "packages/ui" node. This node does not have a "build" task. The "packages/ui" node has another line to a "packages/core" node that does have a "build" task.

你可以将此图想象成一系列步骤:

¥You can think of this graph in a series of steps:

  • docs 应用仅依赖于 ui

    ¥The docs app only depends on ui.

  • ui 包没有构建脚本。

    ¥The ui package does not have a build script.

  • ui 软件包的依赖包含一个 build 脚本,因此任务图知道要包含这些脚本。

    ¥The ui package's dependencies have a build script, so the task graph knows to include those.

在这种情况下,Turborepo 将 ui 包称为“中转节点”,因为它没有自己的 build 脚本。由于 Turborepo 没有 build 脚本,因此 Turborepo 不会为其执行任何操作,但它仍然是构建图的一部分,以便包含其自身的依赖。

¥Turborepo calls the ui package a Transit Node in this scenario, because it doesn't have its own build script. Since it doesn't have a build script, Turborepo won't execute anything for it, but it's still part of the graph for the purpose of including its own dependencies.

传输节点作为入口点

¥Transit Nodes as entry points

如果 docs/ 包没有实现 build 任务会怎么样?在这种情况下,你期望发生什么?uicore 包是否仍应执行其构建任务?这里会发生什么?

¥What if the docs/ package didn't implement the build task? What would you expect to happen in this case? Should the ui and core packages still execute their build tasks? Should anything happen here?

Turborepo 的思维模型是任务图中的所有节点都是相同的。换句话说,无论 Transit 节点出现在图中的哪个位置,它们都会包含在图中。这种模型可能会产生意想不到的后果。例如,假设你已将 build 任务配置为依赖于 ^test

¥Turborepo's mental model is that all nodes in the Task Graph are the same. In other words, Transit Nodes are included in the graph regardless of where they appear in the graph. This model can have unexpected consequences. For example, let's say you've configured your build task to depend on ^test:

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^test"]
    }
  }
}

假设你的 monorepo 包含许多应用和许多包。所有包都包含 test 任务,但只有一个应用包含 build 任务。Turborepo 的思维模型是,当你运行 turbo run build 时,即使应用未实现 build,所有依赖包的 test 任务都会显示在图中。

¥Let's say your monorepo has many apps and many packages. All packages have test tasks, but only one app has a build task. Turborepo's mental model says that when you run turbo run build, even if an app doesn't implement build the test task of all packages that are dependencies will show up in the graph.