Nx 中 nx:run-commands 执行器完全指南:命令编排、参数转发与 Affected 智能执行
2026/9/12 17:41:53 网站建设 项目流程

Nx 中 nx:run-commands 执行器完全指南:命令编排、参数转发与 Affected 智能执行

【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx

nx:run-commands是 Nx 内置的通用执行器,允许你在不编写自定义执行器代码的情况下,把任意 shell 命令纳入 Nx 的任务图与项目图体系。本文基于 Nx 仓库中的官方示例文档 packages/nx/docs/run-commands-examples.md,结合其源码实现与配置 Schema,系统讲解命令串联/并行、工作目录切换、参数插值与转发、自定义完成条件,以及配合nx affected实现按变更范围智能执行的全部实战用法。读完本文,你将能够把项目中的脚本、文档生成、构建命令等任意流程无缝接入 Nx 的缓存、并行与增量执行体系。

基本用法:用 project.json 定义一条自定义命令

nx:run-commands的核心是把一段 shell 命令包装成一个标准的 Nx target,从而让这条命令享受 Nx 任务执行体系的全部能力(依赖调度、缓存、并行、Affected 等)。

在项目(这里以frontend项目为例)的project.json中配置如下 target:

{ // ... "targets": { //... "ls-project-root": { "executor": "nx:run-commands", "options": { "command": "ls apps/frontend/src" } } } }

然后在终端执行:

nx run frontend:ls-project-root

nx run <project>:<target>是 Nx 运行任意 target 的统一入口。这里ls-project-root执行的就是ls apps/frontend/src

需要指出的是,project.json只是 Nx 项目配置的入口之一,它由 packages/nx/src/plugins/project-json/build-nodes/project-json.ts 等插件读取并归并进最终的项目配置中;而在单仓内没有显式project.json的项目,也可以通过package.json脚本配合 Nx 进行执行。

串联多条命令(Chaining Commands)

options.commands选项接受任意数量的命令。默认情况下,这些命令并行执行;若需要按顺序逐个执行,将parallel设置为false即可:

"create-script": { "executor": "nx:run-commands", "options": { "commands": [ "mkdir -p apps/frontend/scripts", "touch apps/frontend/scripts/my-script.sh", "chmod +x apps/frontend/scripts/my-script.sh" ], "parallel": false } }

上面的例子依次创建目录、创建脚本文件并赋予可执行权限——这类有先后依赖的步骤必须串行执行。根据 schema.json 中的定义,parallel的默认值为true,也就是说你不显式设置时命令是同时启动的;只有明确需要顺序执行时才需要"parallel": false

从源码实现看,并行与串行分别由 running-tasks.ts 中的ParallelRunningTasksSeriallyRunningTasks两个类承载,runCommands会根据options.parallel选择对应的执行器:

const runningTask = isSingleCommandAndCanUsePseudoTerminal ? await runSingleCommandWithPseudoTerminal(...) : options.parallel ? new ParallelRunningTasks(normalized, context, resolvedTaskId) : new SeriallyRunningTasks(normalized, context, tuiEnabled, resolvedTaskId);

(见 packages/nx/src/executors/run-commands/run-commands.impl.ts)

设置工作目录(Setting the cwd)

通过cwd选项,可以让每条命令都在指定目录下运行。例如下面的配置使所有命令都在apps/frontend目录中执行:

"create-script": { "executor": "nx:run-commands", "options": { "cwd": "apps/frontend", "commands": [ "mkdir -p scripts", "touch scripts/my-script.sh", "chmod +x scripts/my-script.sh" ], "parallel": false } }

注意这里命令里的路径是相对apps/frontend的:mkdir -p scripts实际创建的是apps/frontend/scripts

关于cwd的取值规则,schema.json 给出了明确说明:

  • 不指定时,命令在工作区根目录运行;
  • 指定相对路径时,命令在该相对工作区根目录的路径下运行;
  • 指定绝对路径时,命令在绝对路径下运行。

参数插值(Interpolating Args)

在脚本中可以通过{args.[someFlag]}语法使用自定义参数:

"create-script": { "executor": "nx:run-commands", "options": { "cwd": "apps/frontend", "commands": [ "mkdir -p scripts", "touch scripts/{args.name}.sh", "chmod +x scripts/{args.name}.sh" ], "parallel": false } }

有两种方式传参运行:

nx run frontend:create-script --args="--name=example"

或者更简洁的写法(参数直接跟在 target 后面):

nx run frontend:create-script --name=example

参数插值的底层实现位于 run-commands.impl.ts 的interpolateArgsIntoCommand函数中。它用正则/{args\.([^}]+)}/g匹配{args.xxx}占位符,并从parsedArgs中取出对应值进行替换;若某个占位符在参数中不存在,则替换为空字符串。Nx 通过 yargs-parser 对命令行参数进行解析(parseArgs函数),解析时启用了 camel-case 展开,因此--some-flag=1--someFlag=1这类写法都能被识别。

另外还有两种值得了解的用法:

  • {args}(不带属性)会被替换为全部参数拼接而成的字符串
  • 注意约束:一条命令不能同时混用{args}{args.*}两种语法,否则运行时会抛出错误(interpolateArgsIntoCommand中会做显式校验)。

关于参数转发的注意点

需要特别留意的是:命令列表中任何未包含插值语法的命令,默认仍会把传入的全部参数原样追加到命令尾部。例如给定配置:

"create-script": { "executor": "nx:run-commands", "options": { "commands": [ "echo {args.name}", "echo done" ], "parallel": false } }

运行nx run frontend:create-script --name=example时,第二条命令echo done也会被追加--name=example,实际执行的是echo done --name=example

如果某些命令不应该接收这些参数,就在该命令对象上显式设置forwardAllArgs: false

"create-script": { "executor": "nx:run-commands", "options": { "commands": [ "echo {args.name}", { "command": "echo done", "forwardAllArgs": false } ], "parallel": false } }

参数转发(Arguments Forwarding)

当命令中没有插值占位符时,所有参数默认都会被转发给命令本身。这一特性在你需要把原始参数字符串原样传给命令时非常有用。

例如运行:

nx run frontend:webpack --args="--config=example.config.js"

配合如下配置:

"webpack": { "executor": "nx:run-commands", "options": { "command": "webpack" } }

实际执行的就是:webpack --config=example.config.js

这个行为由interpolateArgsIntoCommand中的forwardAllArgs分支实现:当命令不含{args...}占位符且forwardAllArgs为真时,会把未知选项(unknownOptions)、args以及未解析参数(__unparsed__)三部分拼接后追加到命令末尾(见 packages/nx/src/executors/run-commands/run-commands.impl.ts)。其中forwardAllArgs的默认值为true(见 schema.json)。

如需禁用转发,则必须把单条命令展开为对象形式,并设置forwardAllArgs: false

"webpack": { "executor": "nx:run-commands", "options": { "commands": [ { "command": "webpack", "forwardAllArgs": false } ] } }

forwardAllArgs既可以配置在单条命令对象上(RunCommandsCommandOptions.forwardAllArgs),也可以配置在options顶层作为默认值;单条命令的取值优先级更高:源码中取的是c.forwardAllArgs ?? options.forwardAllArgs ?? true

简写形式(Shorthand)

当只需要运行一条命令时,可以直接在 target 中写command字段,而省略executoroptions两层包装——Nx 会识别这种简写形式,自动将其视为nx:run-commands

"webpack": { "command": "webpack" }

这与完整的executor: "nx:run-commands"+options.command写法完全等价,是官方推荐的单命令最简洁写法。需要注意的是,简写形式只支持单条命令场景;需要多条命令或更复杂的选项(如cwdreadyWhen)时仍应使用完整写法。

自定义完成条件(Custom done conditions)

正常情况下,run-commands会等待所有命令都运行结束才判定任务完成。如果你不需要等待全部命令结束,可以设置一个特殊字符串:一旦该字符串出现在子进程的stdoutstderr中,就立即判定任务完成。

"finish-when-ready": { "executor": "nx:run-commands", "options": { "commands": [ "sleep 5 && echo 'FINISHED'", "echo 'READY'" ], "readyWhen": "READY", "parallel": true } }
nx run frontend:finish-when-ready

上面的配置会立即完成,而不会等待 5 秒——因为echo 'READY'的输出已经满足完成条件。

当多条命令并行运行时,你可能需要等待多个字符串同时出现在输出中。例如同时启动多个开发服务器,希望所有服务都就绪后再继续:

"finish-when-multiple-ready": { "executor": "nx:run-commands", "options": { "commands": [ "sleep $[ ( $RANDOM % 10 ) + 1 ] && echo 'READY1' && sleep 3600", "sleep $[ ( $RANDOM % 10 ) + 1 ] && echo 'READY2' && sleep 3600", ], "readyWhen": ["READY1", "READY2"], "parallel": true } }
nx run frontend:finish-when-multiple-ready

上述两条命令都会在随机 1~10 秒内输出各自的 READY 标记(随后各自sleep 3600挂起);只要READY1READY2都出现过,任务就立即完成,无需等待那额外的一个小时。

关于readyWhen,schema.json 与源码共同给出了以下关键约束与行为:

  • readyWhen接受字符串或字符串数组
  • 运行多条命令时,readyWhen只能在parallel: true下使用。源码runCommands中对此有显式校验:若设置了readyWhenparallel为假,会抛出"readyWhen" can only be used when "parallel=true"错误(见 run-commands.impl.ts);
  • 未设置readyWhen时,任务在全部子进程结束后才完成;
  • 在并行 +readyWhen模式下,任一子进程以非零码退出时会输出Warning: command "..." exited with non-zero status code警告,任务随之结束(见 running-tasks.ts 中ParallelRunningTasks.run的实现)。

从实现细节看,readyWhen的匹配是逐个子进程监听输出normalizeOptions会把readyWhen(字符串或数组)规整为{ stringToMatch, found }[]状态数组,交给每个RunningNodeProcess实例去扫描输出流。

与 Nx Affected 结合:按变更范围执行自定义命令

run-commands的真正威力在于它经由nx运行,而 Nx 掌握着完整的项目图(project graph)。因此,你可以让自定义命令只针对"受变更影响(affected)"的项目执行。

例如为frontendapi两个项目分别配置文档生成命令:

//... "frontend": { "targets": { //... "generate-docs": { "executor": "nx:run-commands", "options": { "command": "npx compodoc -p apps/frontend/tsconfig.app.json" } } } }, "api": { "targets": { //... "generate-docs": { "executor": "nx:run-commands", "options": { "command": "npx compodoc -p apps/api/tsconfig.app.json" } } } }

然后使用nx affected运行:

nx affected --target=generate-docs

这样,只有发生变更的项目才会触发文档生成:如果本次提交只改了frontend的代码,就只运行npx compodoc -p apps/frontend/tsconfig.app.jsonapi的文档生成任务会被跳过。这正是 Nx 在 CI 中大幅节省时间的核心机制之一——把自定义脚本也纳入项目图驱动的增量执行体系。

更多实用选项

除文档示例覆盖的内容外,schema.json 还定义了以下常用选项,可用于更精细的控制:

选项类型默认值说明
commandstring | string[]要执行的命令;数组形式表示按部分拆分的同一命令
commandsarray在子进程中运行的命令列表;每项可为字符串或对象(对象支持commandforwardAllArgsprefixprefixColorcolorbgColordescription字段)
parallelbooleantrue是否并行运行各命令
readyWhenstring | string[]出现于 stdout/stderr 即视为任务完成的字符串;多命令时仅限parallel: true
cwdstring工作区根目录命令的工作目录;相对路径基于工作区根,绝对路径按原值使用
argsstring | string[]额外参数,配合{args.xxx}插值使用
forwardAllArgsbooleantrue无插值时是否把所有参数转发给命令
envFilestring自定义.env文件路径
envobject注入命令的环境变量;优先级高于.env文件
colorbooleanfalse是否在命令输出中使用颜色

几点值得注意的行为与约束:

  • envenvFileenv中的变量会优先于.env文件中的同名变量(schema 明确说明 "This property has priority over the.envfiles");
  • 输出着色选项prefixprefixColorcolorbgColor等输出样式选项只能在parallel: true时使用,源码中对此同样有显式校验,违规配置会直接报错(见 run-commands.impl.ts)。可用颜色包括blackredgreenyellowbluemagentacyanwhitebgColor对应bgBlack~bgWhite);
  • description:仅用于在配置中内联记录命令用途,不参与命令的实际执行(源码注释明确说明这一点);
  • 空命令列表commands为空数组时,任务会立即以成功状态返回,不会启动任何子进程;
  • 至少提供一个命令:Schema 要求commandscommand二者至少声明其一(oneOf约束)。

小结

nx:run-commands是 Nx 中"零代码接入"的万能执行器:从单条命令的简写,到多条命令的串并行编排、cwd工作目录控制、{args.xxx}参数插值与forwardAllArgs转发策略、readyWhen自定义完成条件,再到与nx affected结合的按变更范围执行,它把任意 shell 流程无缝纳入了 Nx 的项目图、任务依赖、并行调度与增量执行体系。本文所有配置示例均来自官方示例文档 packages/nx/docs/run-commands-examples.md,选项细节与行为约束可进一步参考 schema.json 与实现源码 run-commands.impl.ts、running-tasks.ts。

【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询