
在 PNPM Workspace 中使用 Nx 高效运行与管理任务从pnpm --filter到nx run-many【免费下载链接】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在基于 PNPM workspace 的 monorepo 中开发者通常用pnpm --filter pkg script逐个调用各包的package.json脚本但随着项目增多手动定位包名、手动串行执行变得越来越低效。本篇教程来自 Nx 官方课程《From PNPM Workspaces to Distributed CI》课程大纲见 course.md的第二课以 Tasker 应用一个基于 Next.js、以 PNPM workspace 组织的任务管理应用为例讲解如何用 Nx 的任务执行能力统一接管 PNPM workspace 中的脚本。学完本篇你将掌握 Nx 运行单任务、多任务、受影响任务的完整命令语法理解任务流水线task pipeline的排序原理并能在源码层面看懂run-many的项目筛选机制。一、为什么要用 Nx 来跑 PNPM 脚本在引入 Nx 之前运行 Tasker 中tasker/web包的构建命令是这样的pnpm --filter tasker/web build而接入 Nx通过nx init详见 01-nx-init.md之后同样的构建变成了pnpm nx build tasker/web两种写法完成同一件事但后者带来三个关键收益统一入口Nx 读取package.json的scripts原样作为任务无需为每个包单独配置即可通过nx命令运行可缓存Nx 会为每个任务计算输入指纹命中缓存时直接恢复产物而跳过真实执行这是本课之后 03-configure-cache.md 的内容可排序、可并行Nx 基于项目依赖图自动决定多个任务的执行顺序并在无依赖的任务之间并行执行。Nx 官方文档 Run Tasks 对这一能力做了完整定义无论 workspace 中有一个还是数百个项目Nx task runner 都能做到——为多个项目的多个目标并行运行、按任务流水线排序执行、只运行受变更影响的项目以及通过缓存加速执行。二、任务从哪里来三种定义来源Nx 的任务task即某个项目上的一个可执行目标 target来自三个来源它们会被合并成该项目的完整任务集来源说明示例位置package.json的scripts直接沿用现有 npm scripts零配置即可被 Nx 运行libs/mylib/package.jsonproject.json的targets显式定义任务可用command字段写任意 CLI或用executor复用 Nx 内置执行器libs/mylib/project.jsonNx 插件推断inferred tasks插件扫描工具链配置文件如vite.config.ts、.eslintrc.json、jest.config.ts自动生成任务由nx.json中plugins配置控制以package.json形式定义任务最简单// libs/mylib/package.json { name: mylib, scripts: { build: tsc -p tsconfig.lib.json, test: jest } }若需要显式控制可改用project.json// libs/mylib/project.json { root: libs/mylib, targets: { build: { command: tsc -p tsconfig.lib.json }, test: { executor: nx/jest:jest, options: { } } } }第三种方式由 Nx 插件自动推断。例如在nx.json中注册nx/vite/plugin、nx/eslint/plugin、nx/jest/plugin后插件会为每个符合规则的项目自动生成build、test、lint、serve等任务// nx.json { plugins: [ { plugin: nx/vite/plugin, options: { buildTargetName: build, testTargetName: test, serveTargetName: serve, previewTargetName: preview, serveStaticTargetName: serve-static } }, { plugin: nx/eslint/plugin, options: { targetName: lint } }, { plugin: nx/jest/plugin, options: { targetName: test } } ] }官方文档明确指出无论任务来自哪种来源Nx 都会按原样读取配置因此一个 workspace 可以不添加任何任务配置就通过 Nx 运行。这正是 PNPM workspace 接入 Nx 后能立刻用nx跑tasker/web各脚本的根本原因。更完整的配置项说明见 project-configuration.mdoc。三、运行单个任务两种等价语法Nx 的通用任务运行语法为nx target project # 简写 nx run project:target # 完整写法本课的示例在 PNPM workspace 下通过 pnpm 调用 Nx为pnpm nx build tasker/web其中tasker/web是项目名与包名一致build是任务名。nx run tasker/web:build是等价的完整写法。官方教程 running-tasks.mdoc 还给出了另外两种便捷用法nx run my-app:build # 完整写法 nx build my-app # 简写任务名不与 Nx 内置命令冲突时可用 cd apps/my-app nx build # 进入项目目录后可省略项目名Nx 从当前目录解析项目四、运行多个任务run-many当需要一次性在多个项目上执行一个或多个任务时使用run-many命令。官方文档 run-tasks.mdoc 中的典型用法如下对仓库中所有项目运行build任务npx nx run-many -t build对所有项目运行build、lint、test三个任务npx nx run-many -t build lint test只对header和footer两个项目运行这三个任务npx nx run-many -t build lint test -p header footer其中-t是--targets的简写目标任务多个用空格分隔-p是--projects的简写项目名支持逗号或空格分隔也支持 glob 模式。教程 running-tasks.mdoc 中的等价写法如下nx run-many --targets build nx run-many --targets build test lint nx run-many --targets build --projects my-appNx 会并行执行这些任务同时根据项目依赖与任务流水线配置保证执行顺序正确。并发度可通过相关配置控制默认即开启并行。五、只跑受影响的项目affected在 CI 或日常开发中更常见的是只运行本次变更影响到的项目。Nx 通过计算项目依赖图与 Git 基线对比得出 affected 项目集合npx nx affected -t test该命令只会对本次 PR 变更影响到的项目运行test任务从而大幅减少 CI 耗时。affected与run-many共享-t、-p等参数语义其详细机制参见 affected 相关文档若该文件在当前仓库的对应目录不存在可参考astro-docs中features/run-tasks.mdoc的 affected 章节。六、定义任务流水线targetDefaults.dependsOn很多场景下任务之间存在先后依赖比如必须先构建shared-ui才能构建引用它的myreactapp。Nx 能自动识别项目之间的依赖关系见 explore-graph.mdoc但需要你在配置中声明哪些 target 之间的顺序是重要的。在nx.json中通过targetDefaults声明// nx.json { targetDefaults: { build: { dependsOn: [^build] } } }dependsOn: [^build]中的^前缀表示当前项目依赖的那些项目上的 build 任务。执行nx build myreactapp时Nx 会先构建shared-ui和feat-products它们又被myreactapp依赖再构建myreactapp本身。任务依赖可以定义在nx.json中全局生效也可以定义在某个项目自己的project.json中局部生效。当前 Nx 仓库自身的 nx.json 就是一个真实的大型示例——其中build的targetDefaults同时声明了dependsOn: [^build, typecheck, build-base]与inputs: [production, ^production]、cache: true展示了任务依赖、缓存输入、缓存开关如何组合使用。七、根级任务对整个代码库生效的脚本某些任务面向整个代码库如生成文档站点不属于任何单个项目。为了让这类任务也能享受 Nx 的缓存与流水线能力可以将其定义在根级package.json或project.json中// package.json根 { name: myorg, scripts: { docs: node ./generateDocsSite.js }, nx: {} }注意根package.json上的nx: {}属性是必需的它告知 Nx 这是一个根级项目该对象还可以扩展为指定缓存输入与输出。若希望保持npm run docs或pnpm run docs的调用方式同时仍然走 Nx 缓存可以把脚本命令包一层nx exec// package.json根 { name: myorg, scripts: { docs: nx exec -- node ./generateDocsSite.js }, nx: {} }随后统一通过 Nx 调用npx nx docs八、源码视角run-many是如何挑选项目的要深入理解 Nx 的任务运行行为可以阅读当前仓库中run-many命令的真实实现。命令的 yargs 入口定义在 command-object.ts它声明了run-many命令并组合了withRunManyOptions、withTargetAndConfigurationOption、withOutputStyleOption、withTuiOptions等参数解析器。参数层的细节可以在 shared-options.ts 中看到-t/--targetsalias: [target, t]通过parseCSV支持逗号/空格分隔的多个任务名见withTargetAndConfigurationOption-p/--projectsalias: p同样是逗号/空格分隔的项目名或模式见withRunManyOptions--all注释为「已弃用」因为run-many在未提供--projects时默认就运行所有项目默认值default: true。真正的执行逻辑在 run-many.tsreadNxJson()读取工作区配置splitArgsIntoNxArgsAndOverrides把命令参数拆分为 Nx 参数与传递给任务本身的参数覆盖overrides即--之后的内容createProjectGraphAsync()构建项目依赖图projectsToRun()完成项目筛选若未提供--projects则遍历全部项目runnableForTarget()只保留至少拥有其中一个目标任务的项目projectHasTarget(project, target)用户指定的项目若没有对应目标任务会输出警告而不是报错--exclude支持从选中集合中剔除指定项目最终调用runCommand()来自tasks-runner统一执行任务调度包括并行调度与按dependsOn排序。从这段实现可以推断nx run-many -t build之所以能自动跳过没有 build 任务的包正是因为runnableForTarget只收集了projectHasTarget为真的项目——这在混合型 PNPM workspace部分包只有test脚本、部分包有build脚本中非常实用。九、小结本课的核心要点可以归纳为一张迁移清单场景原来PNPM 原生接入 Nx 后跑单个包的任务pnpm --filter tasker/web buildpnpm nx build tasker/web全仓跑某个任务逐个包执行nx run-many -t build全仓跑多个任务手写循环nx run-many -t build lint test指定项目跑任务pnpm --filter组合nx run-many -t build -p header footer只跑受影响项目人工判断nx affected -t test保证任务顺序手动编排targetDefaults的dependsOn: [^build]Nx 的任务运行能力是后续课程缓存配置、任务流水线、CI 优化与远程缓存的地基只有先学会用统一的nx target project语法接管 PNPM 脚本才能进一步为这些任务配置缓存输入输出、定义流水线排序并最终在 CI 中实现任务的分布式执行。【免费下载链接】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),仅供参考