Nx
是一个开源的功能强大的构建系统,用于提高开发人员生产力、优化 CI 性能和维护代码质量的工具和技术。
一、心智模型 (Mental Model)
Nx
是一个基于 VS Code
的构建工具。具有强大的核心且由元数据驱动,可以通过插件进行扩展能力。Nx
使用一些概念来 有效
和 高效
的驱动, 你的第一存储库。本指南涵盖了项目图 (graphs
),甘特图(task graphs
)、受影响的命令(affected commands
),计算(computation hashing
)和缓存(caching
)的心理模型。
二、项目图 (The project graph)
项目图
用于反映 存储库中的源代码
以及 未在存储库中编写
的所有外部依赖项,例如: Webpack
、React
、Angular
等。
对于 Nx
,项目中的节点 (Node
)是在 project.json
文件中定义的。你可以 手动
定义节点之间的依赖关系,但不必经常这样做。Nx
分析文件的源代码、已安装的依赖、TypeScript 文件以及其他为你这些依赖的内容。 Nx
还缓存项目图,因此它只重新分析你已更改的文件。
每次分析完成之后,Nx
都会提供更新的图表。
三、元数据驱动
Nx
中的所有内容都带有 元数据
已实现工具化。默认值
、验证
、自动完成
工作等都在架构中定义,而不是代码中。此元数据由 Nx
本身、VSCode
和 WebStorm
集成、GitHub
集成以及 第三方
工具使用。
通过 Nx
使用元数据,这些工具能够实现更加丰富的体验。
四、任务图
Nx
使用 项目图
来创建 任务图
。每当运行任何内容时,Nx
都会从 项目图
创建一个 任务图
,然后执行该图中的 任务
。
例如,nx test lib
创建一个具有 单个节点
的任务图:
任务是对目标的调用。如果调用 同一目标
两次,则会创建两个任务。
Nx
使用 项目图
,但任务图和项目图不是同构的,这意味着它们没有直接连接。在上面的例子中,app1
依赖 app2
于 lib
,但是运行 nx run-many -t test -p app1 app2 lib
,创建的任务图将如下所示:
尽管应用程序依赖于 lib
测试,但测试 app1
并不依赖于测试 lib
。这意味着这两个任务可以并行运行。
让我们看看 测试目标
依赖于它的依赖项。
{
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/app1"],
"dependsOn": ["^test"],
"options": {
"jestConfig": "apps/app1/jest.config.js",
"passWithNoTests": true
}
}
}
这样,运行相同的测试命令将创建以下 任务图
:
这对于构建来说通常更有意义,在哪里构建 app1
,你想 lib
首先构建。您还可以定义同一项目的目标之间的类似关系,包括依赖于构建的测试目标。
任务图
可以包含不同的目标
,并且这些 目标
可以并行运行
。例如,当 Nx
正在构建时 app2
,它可以 app1
同时进行测试。
Nx
还以正确的 顺序运行
任务图中的任务。Nx
并行执行任务可加快整体执行时间。
五、受影响的命令
当运行 nx test app1
时,Nx
运行 app1:test
任务及其依赖的所有任务。
当运行时,在告诉 Nx
对两个任务和 nx run-many -t test -p app1 lib
执行相同的操作。 app1:test
lib:test
当运行时 nx run-many -t test --all
,Nx
对所有项目执行此操作。
随着工作空间的增长,重新测试所有项目变得太慢。为了解决这个问题,Nx
实施了代码更改分析,以获得需要重新测试的最小项目集
。它是如何工作的?
当运行 nx affected -t test
时,Nx
会查看项目 PR
中更改的文件,它将查看更改的性质(您在这些文件中到底更新了什么),并使用它来计算工作区中可以更改的项目列表。受此变化影响。然后它 run-many
使用该列表运行命令。
例如,如果我的 PR
发生变化 lib
,然后我运行 nx affected -t test
,Nx
会发现 app1
并 app2
依赖 lib
,因此它将调用 nx run-many -t test -p app1 app2 lib
。
Nx
分析变化的性质。例如,如果更改 package.json
中 Next.js
的版本,Nx
知道不会 app2
受其影响,因此只会重新测试 app1
。
六、计算哈希和缓存
Nx
以正确的顺序运行任务图中的任务。在运行任务之前,Nx
计算其计算哈希。只要计算哈希相同,运行任务的输出就相同。
Nx
是如何做到的?
默认情况下,say 的计算哈希nx test app1
包括:
app1
和的所有源文件lib
。- 相关全局配置。
- 外部依赖项的版本。
- 用户配置的运行时值。
CLI
命令标志。
此行为是可定制的。例如,lint
检查可能仅依赖于项目的源代码和全局配置。构建可以依赖于已编译库的 dts
文件而不是其源。
Nx
计算出任务的哈希值后,它会检查之前是否运行过这个精确的计算。首先,它在本地进行检查,然后如果丢失,如果配置了远程缓存,则进行远程检查。
如果 Nx
找到计算,Nx
会检索它并重播它。Nx
将正确的文件放入正确的文件夹中并打印终端输出。因此,从用户的角度来看,命令运行相同,只是速度快得多。
如果 Nx
找不到此计算,Nx
会运行该任务,完成后,它会获取输出和终端输出并将其存储在本地(如果远程配置)。所有这一切都是透明发生的,因此您不必担心。
尽管从概念上讲这相当简单,但 Nx
对此进行了优化,以使这种体验对您有利。例如 ,Nx
:
- 捕获
stdout
和stderr
以确保重放的输出看起来相同,包括在Windows
上。 - 通过记住哪些文件在哪里重播来最小化
IO
。 - 仅在处理大型任务图时显示相关输出。
- 提供对缓存未命中进行故障排除的功能。以及许多其他优化。
随着工作区的增长,任务图看起来更像这样:
所有这些优化对于使 Nx
可用于任何重要的工作空间至关重要。仅发生最少量的工作。其余部分要么保持原样,要么从缓存中恢复。
七、分布式任务执行
Nx
支持跨多台机器运行命令。您可以手动设置或使用 Nx Cloud
阅读两种方法的比较。
当使用 分布式任务
执行时,Nx
能够在许多代理上而不是在本地 运行
任何 任务图
。
例如,nx affected --build
不会在本地运行构建(对于大型工作区,这可能需要几个小时)。相反,它会将任务图发送到 Nx Cloud
。然后,Nx
云代理将选取它们可以运行的任务并执行它们。
请注意,这是透明发生的。如果代理构建 app1
,它将获取输出(如果它还没有 lib
)。
当代理完成任务时,您调用的主要作业 nx affected --build
将开始接收创建的文件和终端输出。
完成后 nx affected --build
,机器将拥有构建文件和所有终端输出,就像在本地运行一样。
八、总结
Nx
能够分析源代码
以创建项目图
。Nx
可以使用项目图
和有关项目目标的信息来创建任务图
。Nx
能够执行代码更改分析,为项目的PR
创建最小的任务图
。Nx
支持计算缓存,永远不会执行相同的计算两次。该计算缓存
是可插拔
的并且可以是分布式的。