Nx 24:基于任务的影响分析、waitFor、细粒度 E2E 缓存及支持智能体的迁移
Nx 24 发布了。除了本次版本本身,这篇文章还会介绍 Nx 23 到现在之间落地的一些重要功能,帮你查漏补缺。
基于任务的 affected 现在是默认行为
过去 nx affected 是在项目层面工作的:只要改动涉及某个项目,这个项目的所有任务都会执行。
基于任务的 affected 则类似缓存机制,它根据每个任务的 inputs 和 outputs 来判断你的改动是否影响到它。比如一个 PR 只改了某个 spec 文件,现在只会运行该项目的 test,而不会再触发 build。对 build、test、e2e 这类 inputs 定义较窄的 target,效果最明显——而这通常正是 CI 耗时最多的地方。
我们在 Nx 23.3 中以可选方式上线了这项功能,到 Nx 24 已成为默认行为。新建的 workspace 直接生效;升级已有 workspace 时,迁移会在 nx.json 中设置 affected.legacy: true,让你继续使用项目级选择,直到你手动移除:
{
"affected": {
"legacy": true
}
}删掉这一项即可切换到新行为。如果某个任务出现(或没出现)而你不确定原因,可以用 --explain 查看受改动影响的任务以及读取它们输出的任务,不会实际运行任何东西:
nx affected -t build --explainaffected 文档详细说明了 Nx 如何判定任务受影响,以及对于手写 inputs 的 target 需要注意什么。
动态任务打包与 Ultracache
基于任务的 affected 只是 CI 优化的第一层,接下来是通过 Ultracache 实现远程缓存,以及通过动态任务打包实现任务分发。
动态任务打包能减少你付费的 VM 分钟数。它会记录每个任务的 CPU 和内存使用特征,据此在同一台机器上并行运行更多任务,让同样的工作消耗更少的 VM 分钟。部分客户已经节省了 35% 到 50% 的 VM 分钟数。你可以在 Nx Cloud workspace 设置中开启,文档解释了动态任务打包的工作原理。
Ultracache 省去了手动配置缓存输入和输出的繁琐工作。它会在 CI 中记录每个任务读取了哪些文件,并据此对任务进行哈希计算。这样一来,错误的 inputs 配置项就不会再导致误判缓存命中。所有订阅计划(包括 Hobby)的新工作区默认都会开启该功能。对于已有工作区,你可以在 Nx Cloud 工作区设置中手动启用。
在我们包含 511 个项目的 单体仓库基准测试中,该组合让 CI 提速 9.2 倍,同时将计算资源消耗降低了 52%。我们目前正在进一步挖掘计算资源的节省潜力。
还在使用单体应用?由于 Ultracache 基于任务实际读取的内容工作,因此不依赖你的代码结构。我们在一个 拥有 30 万行代码的单项目 React 应用上进行了基准测试:CI 提速 11.7 倍,计算资源消耗降低 78%。完整的配置和详细数据见 单体仓库和 单体应用基准测试仓库。
更多细节请参阅我们的 发布公告。
优化 CI 中的 E2E 测试运行
E2E 测试通常是 CI 中最耗时的环节,且如今 Agent 正在编写越来越多的此类测试。Atomizer已经将单个大型 E2E 任务拆分为针对每个 spec 文件的独立任务,以便 Nx Cloud 能将其分布到不同机器上。然而在过去,这些拆分后的任务会对整个应用进行哈希,导致任何地方的编辑都会触发所有 spec 重新运行。
原因在于开发服务器。Spec 文件并不直接导入被测试的代码。它向以独立任务运行的服务器发送请求,因此 Nx 无法判断 spec 具体测试了应用的哪部分代码,只能对全部代码进行哈希。
Nx 24 在 spec 文件顶部增加了两个指令,使 Nx 能够基于被测试代码来缓存每个 spec:
@nx-ignore-server-inputs@nx-depends-on
如果你正在使用 Ultracache,请添加 // @nx-ignore-server-inputs 并导入该 spec 所测试的页面或组件:
// @nx-ignore-server-inputs
import '@myorg/checkout/checkout-page';
import { expect, test } from '@playwright/test';
...
该指令会把 app server 从 spec 的哈希中剔除。Nx 仍会构建并启动服务器,但服务器不再影响 spec 的哈希。Ultracache 会记录该 spec 在上次 CI 运行时读取的文件(包括 checkout 页面及其导入的模块),并基于这些文件计算哈希。
如果 spec 依赖它无法导入的代码,比如外部模板、样式表或其他服务,可以在项目上用 @nx-depends-on 注解声明:
// @nx-depends-on: checkout
import { expect, test } from '@playwright/test';这样当 checkout 或其依赖的项目发生变化时,spec 会重新运行;而改动无关的 search 库则会直接重放缓存结果。这比 Ultracache 记录的粒度更粗,但不依赖 Ultracache 也能工作。
详细内容请参阅文档指南。
等待 dev server 就绪
以前,依赖 serve 的 e2e 任务只要服务器进程一启动就会开始执行,而这时服务器往往还不能接收请求。在 Nx 24 中,任务可以在 dependsOn 条目上设置 waitFor: "ready",等到它依赖的持续任务就绪后再运行:
{
"nx": {
"targets": {
"e2e": {
"dependsOn": [
{ "projects": "shop", "target": "serve", "waitFor": "ready" }
]
}
}
}
}如果你使用 Nx 插件,它们推断出的 serve 和 dev target 已经内置了 readyWhen 检查。对于自定义 target,可以在 readyWhen 中描述 Nx 应如何检测任务是否就绪。可以使用 url、port、command、logMatches 或 signal:
当对该 URL 的 GET 请求返回 200 到 403 之间的状态码时视为就绪。
apps/shop/package.json{
"nx": {
"targets": {
"serve": {
"continuous": true,
"readyWhen": { "url": "http://localhost:4200" }
}
}
}
}port当与该端口的 TCP 连接成功时视为就绪,例如数据库容器。
apps/db/package.json{
"nx": {
"targets": {
"start": {
"continuous": true,
"command": "docker compose up postgres",
"readyWhen": { "port": 5432 }
}
}
}
}command命令以退出码 0 结束即视为就绪。Nx 会在工作区根目录下运行该命令。
apps/db/package.json{
"nx": {
"targets": {
"start": {
"continuous": true,
"command": "docker compose up postgres",
"readyWhen": { "command": "pg_isready -h localhost -p 5432" }
}
}
}
}logMatches任务输出中出现指定文本即视为就绪。传入数组可以等待多个字符串。
apps/api/package.json{
"nx": {
"targets": {
"serve": {
"continuous": true,
"readyWhen": { "logMatches": "Listening at http://localhost:3333" }
}
}
}
}signal由服务端代码自行上报就绪信号。
apps/api/package.json{
"nx": {
"targets": {
"serve": {
"continuous": true,
"readyWhen": { "signal": true }
}
}
}
}apps/api/src/main.tsimport { emitReadySignal } from '@nx/js/ready-signal';
const server = app.listen(port, () => {
emitReadySignal(server);
});自动推断出的 Cypress 和 Playwright e2e 任务,现在默认会等待 dev server 就绪后再执行。
所有选项详见项目配置参考文档。
更新的 Node.js 应用脚手架
Nx 24 中,新建的 Node.js 应用默认用 tsc 构建;在使用 TypeScript 路径别名的工作区里,则改用新的 @nx/rolldown 插件。nx serve 会直接用 node --watch 运行 TypeScript 源码,文件变动时自动重启,无需构建步骤(需要 Node.js 22.18 及以上版本)。
serve 任务来自 src/main.ts 的头两行:
#!/usr/bin/env node
// @nx-target-name: serve新的 @nx/js/node 插件会识别 shebang 中包含 node 的文件,并以 @nx-target-name 作为任务名。这对工作区里的任何脚本都有效,比如带 node shebang 的 scripts/seed-db.ts 也会变成一个任务。
创建一个新应用:
nx g @nx/node:app apps/api更多细节见 Node.js 文档。
默认支持 Agentic 迁移
迁移过程最受益于 Agent 的配合。Nx 的迁移脚本负责确定性变更,Agent 则修复因工作区特殊配置而遗漏的部分。
Nx 24 中,迁移以可恢复步骤运行,并提供 Agent 遵循的执行手册,使其能逐个运行并验证各步。
运行 nx migrate latest 后,当执行:
nx migrate --run-migrations…Nx 会询问是否由 AI Agent 执行迁移。

也可以在现有会话中让 Agent 运行迁移,效果相同。

其他 Agentic 改进
自 Nx 23 以来还有几项改动,提升了 Agent 运行 Nx 时的体验。
Agentic nx import 同一模式也适用于仓库导入。 nx import 处理确定性部分(克隆、改写 Git 历史、合并、检测插件),Agent 则应对固定命令无法预见的特殊布局和自定义配置。 Agentic nx import 文章 有详细讲解。
沙箱。 编码 Agent 通常在限制文件和 socket 访问白名单的沙箱中运行。 nx configure-ai-agents 会写入 Claude Code 和其他编码 Agent 运行 Nx 所需
