
从 PNPM Workspace 到分布式 CI用 Nx 将 Tasker 单仓构建与测试提速实战指南【免费下载链接】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 官方仓库中的 pnpm-nx-next 课程整理而成以 Tasker一个基于 Next.js、以 PNPM workspace 组织、通过 Prisma 访问本地数据库并拆分出数据访问包与 UI 组件包的任务管理应用为实战样例逐步讲解如何把现有 PNPM 单仓改造为高性能的 Nx 工作区引入 Nx、配置本地缓存与任务管道、接入 Nx Cloud 远程缓存、用 Nx Agents 做分布式任务执行最终把 Playwright e2e 测试从 20 分钟压缩到 9 分钟。读完本文你将掌握一套可直接复制的“PNPM 单仓 Nx Nx Cloud 分布式 CI”落地方案。课程全景六个增量改造步骤整个课程围绕 Tasker 应用展开采用“小步快跑、每步可验证”的增量策略把单仓优化拆解为六个阶段添加 Nx在不破坏现有 PNPM workspace 结构的前提下引入 Nx 作为任务编排层配置并调优本地缓存让 Nx 正确捕获并恢复构建产物重点是 Next.js 的.next目录定义任务管道Task Pipeline声明任务间的依赖关系确保任务按正确顺序执行如先 build 再 start用远程缓存优化 CI通过 Nx Cloud 让 CI 与本地共享构建结果避免重复劳动调整 CI 配置以启用任务分发引入 Nx Agents跨多台机器并行执行任务拆分并行化 Playwright e2e 测试将整体 20 分钟的 e2e 压到 9 分钟。这六步对应课程中的 00-overview 与 13-outro 之间的 12 节课下文逐一展开。第一步用nx init把 Nx 引入现有 PNPM 工作区Tasker 原本是一个标准的 PNPM workspace 单仓根目录的pnpm-workspace.yaml声明包范围各包通过package.json的scripts维护构建、测试等命令。引入 Nx 有两条路径最小化手工方式只在package.json中加入nx依赖然后手工创建 nx.json 配置文件推荐方式直接运行初始化命令nx initnx init会分析仓库现状向你提出若干问题比如选择要启用的插件、确认哪些脚本要纳入任务编排然后自动生成nx.json与必要的项目配置同时完整保留现有 PNPM workspace 结构——这是本课程反复强调的前提Nx 不是要替代包管理器而是叠加在 PNPM 之上的任务编排与缓存层。作为佐证Nx 官方仓库自身的 nx.json 就同时声明了nxCloudId、nxCloudUrl、namedInputs、targetDefaults与plugins等完整配置说明这正是生产级单仓的标准形态。关于迁移细节可参考课程给出的扩展阅读Adopting Nx 与 Import an Existing Project into an Nx Workspace。第二步用 Nx 统一运行任务替代裸pnpm --filterPNPM 单仓里常见的运行方式是--filter加包名pnpm --filter tasker/web build引入 Nx 后同样的任务可以这样写pnpm nx build tasker/web两种写法的差异在于pnpm --filter只会机械地执行目标包的脚本而pnx nx build会先构建项目图、识别依赖、判断缓存再做最少必要计算仅重新执行受影响的、缓存未命中的任务。对于单个任务与多个任务Nx 的语法是一致的# 运行单个任务 pnpm nx build tasker/web # 同时运行多个任务可混合包名与任务名 pnpm nx run-many -t build testNx 本身是一个任务运行器task runner它不重新发明构建逻辑而是接管“何时运行、按什么顺序运行、是否可复用上次结果”这类编排职责。这正是后续缓存与分布式执行的基础相关能力可参见课程引用的 Run Tasks with Nx。第三步配置本地缓存正确处理.next目录Nx 默认会自动捕获常见的产物目录如dist、build并在任务重跑时从本地缓存直接恢复。但.next目录不在默认列表内——而它是 Next.js 构建的核心产物没有它next start根本无法启动。因此本课的核心是在targetDefaults中为 build 目标显式声明缓存输出。nx.json中与之对应的关键结构是targetDefaults与namedInputs的配合例如 Nx 官方仓库在 nx.json 中对build目标所做的声明{ targetDefaults: { build: { dependsOn: [^build], inputs: [production, ^production], cache: true } } }cache: true开启该目标的缓存能力inputs声明缓存键的输入范围哪些文件变化会导致缓存失效outputs声明产物位置Next.js 项目通常需要显式加上{projectRoot}/.next以及!{projectRoot}/.next/cache之类的排除项确保next build的产物能被正确捕获与恢复。调优缓存的核心心智模型是“输入哈希决定命中与否输出目录决定恢复什么”。只有.next被正确声明为输出开发者本地和 CI 上才能享受“改一行代码 → 只重跑这一个任务 → 其余全部秒级恢复”的体验。详见 Cache Task Results。第四步用 Task Pipeline 保证任务执行顺序所有 Next.js 项目几乎都有这样一对脚本{ scripts: { build: next build, start: next start } }next start只有在项目根目录存在.next目录时才能工作而这个目录由next build生成。也就是说start对build存在隐式依赖。这是任务管道Task Pipeline最典型的应用场景。本课的目标是每次运行start时Nx 自动先执行build或从缓存中恢复其结果。在nx.json的targetDefaults中声明依赖即可{ targetDefaults: { start: { dependsOn: [build] } } }dependsOn支持两种前缀语法build依赖同一项目的build任务^build依赖所有依赖项目的build任务先构建上游库。当 Nx 执行start时它会自动扩展出完整的任务图先跑build成功或缓存命中后再跑start。这种“由管道声明驱动、按图执行”的机制避免了在脚本里手工拼的脆弱写法也让缓存得以作用于图中的每一个节点。官方仓库 nx.json 中大量使用dependsOn: [^build, ...]正是这一能力的生产实践。概念与实操可参考 Defining a Task Pipeline。第五步用 implicitDependencies 补齐项目图Nx 的核心能力之一是在后台构建项目图project graph并据此决定任务如何编排、哪些任务受某个改动影响。可视化项目图的方式pnpm nx graph提示也可以安装Nx ConsoleVSCode / IntelliJ 扩展它能在编辑器内直接可视化项目图、运行任务、查看缓存状态极大提升单仓开发体验详见 editor setup。项目图中绝大多数关系能被 Nx自动发现要么来自package.json的依赖声明要么来自 JS/TS 的 import 语句。但有一类依赖无法被静态分析发现比如 Tasker 中的 Playwright e2e 项目它在代码层面不 import 任何 Next.js 应用的模块却在运行时强依赖——Playwright 必须先把 Next 应用 serve 起来才能跑测试。这种“运行时依赖”需要手工声明方式是给 e2e 项目的project.json添加implicitDependencies属性{ implicitDependencies: [tasker/web] }声明之后项目图才会把 e2e 与 web 应用连起来从而获得两个关键收益nx affected能正确识别“web 应用变了 → e2e 也要重跑”任务分发时e2e 任务会被正确地排在应用启动之后。implicitDependencies的完整字段说明见 project configuration。第六步接入 Nx Cloud——本地与 CI 的桥梁“Smart Monorepos”由 Nx 驱动而“Fast Builds”则由 Nx Cloud 带来。Nx Cloud 是 Nx 的云配套服务把本地缓存的能力延伸进 CI 流水线让大型单仓在 CI 上也能保持高效。本课的操作链路是把 Tasker 单仓推送到 GitHub在 Nx Cloud 上创建一个 workspace将其与 GitHub 仓库关联链接后 Nx Cloud 能感知 PR、提交等事件。完成后本地与 CI 就都能访问 Nx Cloud 提供的远程缓存与分布式任务执行能力。Nx 官方仓库在 nx.json 中同样声明了nxCloudId与nxCloudUrl即该配置的真实形态。接入步骤可参考 Connect to Nx Cloud。用 Nx 命令重构 GitHub ActionsTasker 原本的 CI 脚本基于pnpm --filter本课将它替换为 Nx 命令以提升效率。用生成器直接脚手架出一份新的 CI 配置pnpm nx g ci-workflow该生成器会按最佳实践生成 GitHub Actions workflow其中包含nx affected只跑 PR 受影响的任务等关键环节详见 Run Only Tasks Affected by a PR。同时课程特别提醒一个缓存细节CI 配置本身也应该参与缓存键计算。如果改了.github/workflows/ci.yml但缓存不失效就会得到“配置已变、结果未重算”的陈旧输出。这正是nx.json中namedInputs的用武之地。看 Nx 官方仓库 nx.json 的实际做法{ namedInputs: { sharedGlobals: [ {workspaceRoot}/babel.config.json, {workspaceRoot}/.nx/workflows/agents.yaml, {workspaceRoot}/.github/workflows/ci.yml ], default: [{projectRoot}/**/*, sharedGlobals] } }namedInputs允许把一组文件 glob 或环境变量命名成一个可复用的“输入组”。这里把sharedGlobals含 CI workflow 文件并入default与production意味着任何 CI 配置变更都会自动使相关任务的缓存失效从根本上避免脏缓存问题。为远程缓存配置访问令牌Nx Cloud 内置强大的远程缓存能力因此访问控制至关重要。本课在 Nx Cloud 的 workspace 配置中创建一个访问令牌access token把它以 Secret 形式注入 GitHub Actions从而赋予 CI 对远程缓存的读写权限。令牌的粒度管理详见 Nx CLI and CI Access Tokens。用nx login让开发者机器也接入远程缓存远程缓存不仅服务 CI也可以服务开发者的本地机器。Nx Cloud 使用Personal Access TokenPAT提供细粒度控制按需二选一只读访问开发者只能拉取远程缓存结果为团队节省重复构建时间读写访问开发者既能拉取也能贡献写入缓存让本地构建成果反哺整个团队。开发者在本机执行如下命令完成认证pnpm nx login认证后本地任务会自动读写 Nx Cloud 远程缓存。PAT 的权限配置方法见 Nx Cloud and Personal Access Tokens。调试缓存未命中缓存命中率直接决定收益大小所以弄清“为什么 miss”与“为什么 hit”同样重要。Nx Cloud 提供了对比界面可以把两次 run 并排比较精确定位是哪一份输入变化导致了缓存未命中。常见的未命中原因包括无关文件被纳入输入范围、namedInputs配置过宽、环境变量或全局配置参与哈希等。排查方法论见 Troubleshoot cache misses。第七步用 Nx Agents 把任务分发到多台机器远程缓存很强但存在一个边界场景当核心包频繁变动时缓存会大面积失效此时即使有远程缓存任务仍然要真实执行。单台机器顺序跑仍然很慢。Nx Cloud 内置的Nx Agents特性正是为此设计它自动把任务图中的任务分发到多台机器上并行执行且无需手工拆分任务。本课启用 Nx Agents 只需在 CI 配置中增加一行nx start-ci-run --distribute-on5 linux-medium-js这条命令的含义是启动一次 CI run并通过--distribute-on指定分发规模——5表示 5 个 agentlinux-medium-js是预置的 agent 规格Linux 中等配置、面向 JS/TS 工作负载。Nx 会动态地把任务图调度到这 5 个 agent 上跑完后再由主 job 汇总产物。从源码结构看该命令对应 Nx 仓库中的 start-ci-run 处理器其实现会先检查工作区是否已连接 Nx CloudisNxCloudUsed未连接则给出提示并直接返回已连接则将命令转发给 Nx Cloud 执行——这印证了start-ci-run与 Nx Cloud 的强绑定关系。完整文档见 Distribute Task Execution。第八步并行化 Playwright e2e20 分钟 → 9 分钟e2e 测试在 CI 上往往是最痛苦的环节每个 PR 都想跑但又不想等 30 分钟。Tasker 的 Playwright 测试在 CI 上耗时约 20 分钟本课的目标是把它显著压下来。解法是利用 Nx Playwright 插件自动拆分 e2e 任务把整体 e2e 运行拆成“每个测试文件或每条测试一个独立任务”再让这些原子任务经由 Nx Agents 分散到多台机器上并行执行。这一行为在 Nx Playwright 插件的源码中有直接体现在 插件入口 中插件会为每个 spec 文件生成形如e2e-ci--相对路径的原子化 CI 目标ciTargetName默认e2e-ci并将它们聚合进e2e-ci目标组、统一关闭并行度交由 Nx 调度同时还会生成--merge-reports合并目标把分散机器上的测试报告合并回来。Nx 官方仓库的 nx.json 中也有对应的 Playwright 插件配置targetName与ciTargetName选项以及e2e-ci--**/**这类原子目标模式可作为真实生产的参照。组合效果非常直观任务级并行 机器级分发 报告合并让 20 分钟的整体 e2e 缩短到约 9 分钟且每个 PR 依然能拿到完整、可读的测试报告。原理细节见 Automatically Split E2E Tasks。总结一套可复制的单仓提速路径回顾整条改造链路本质是给单仓叠加三层能力任务编排层Nxnx init无侵入接入 → 统一pnpm nx target project语法 →nx graph可视化项目图 →implicitDependencies补齐静态分析盲区缓存层本地 远程targetDefaults声明cache、inputs、outputs以正确捕获.next等产物 →namedInputs把 CI 配置纳入缓存键 → Nx Cloud 远程缓存用 access token / PAT 控制读写 → 用对比界面调试缓存未命中分布式执行层Nx Agents一行nx start-ci-run --distribute-on开启跨机分发 → Playwright 插件自动原子化拆分 e2e → 20 分钟压到 9 分钟。每一步都是增量、可回滚、可验证的。对任何已经跑在 PNPM workspace 上的 Next.js 单仓而言这套“从 PNPM Workspaces 到分布式 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),仅供参考