
Nx 仓库 Dogfood 实战examples/react/basic 独立 pnpm 工作区如何用 link: 依赖驱动本地插件端到端验证【免费下载链接】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 仓库中的 examples/react/basic 为蓝本完整拆解一个独立 pnpm 工作区 本地插件link:依赖 Nx target 推断的 Dogfood吃自己的狗粮示例它本身是一个由Vite 构建、Vitest 单测、Playwright E2E、ESLint/Oxlint 静态检查的 React 19 应用同时通过link:../../../packages/*直接消费仓库内未发布的本地nx/*插件构建产物。读完本文你将掌握link:依赖如何跨 pnpm workspace 边界生效、插件注册与 target 推断的完整链路、postinstall自动构建依赖包的机制以及一个可用于任何 monorepo 的本地插件回归验证工程模板。一、这个示例是什么技术栈与目标examples/react/basic是一个刻意保持小而完整的 React 应用其核心目标并非演示业务功能而是为 Nx 仓库自身的插件做持续回归验证dogfooding用Vite构建前端产物输出到dist/用Vitest jsdom Testing Library做单元测试用PlaywrightChromium做端到端测试用ESLint配套nx/eslint-plugin做静态检查同时本示例的 nx.json 还注册了nx/oxlint用于 lint target 推断其nx/*依赖全部通过link:指向仓库根目录下的packages/*因此target 推断与运行时辅助函数都来自本地构建而非已发布的 npm 包。页面本身非常简单一个h1渲染Hello there, Welcome examples-react-basic 源码见 src/app/app.tsx。麻雀虽小但它串起了 Nx 工作区中本地开发插件 → 示例应用消费的最短链路。二、目录拓扑一个被隔离的独立工作区examples/react/basic不是仓库根工作区的一部分而是一个自带完整 pnpm 工作区语义的独立目录examples/react/basic/ ├── e2e/ # Playwright 端到端测试 │ └── app.spec.ts ├── src/ │ ├── app/ │ │ ├── app.spec.tsx # Vitest 单元测试 │ │ └── app.tsx # 应用组件 │ ├── main.tsx # React 入口 │ └── styles.css ├── index.html ├── nx.json # 本工作区的插件注册与 namedInputs ├── package.json # link: 依赖 postinstall 构建链 ├── playwright.config.ts # 使用本地 nx/playwright 的 nxE2EPreset ├── pnpm-lock.yaml # 独立的、已提交的锁文件 ├── pnpm-workspace.yaml # 独立 pnpm 工作区标记 ├── tsconfig*.json # 应用 / spec / base 三份 TS 配置 └── vite.config.mts # Vite Vitest 一体化配置pnpm-workspace.yaml 的注释直接说明了设计意图Marks this example as a standalone pnpm workspace: it gets its own pnpm-lock.yaml and install, separate from the repo root workspace. The local nx/* packages are wired in via link: dependencies, which work across workspace boundaries.即该目录拥有自己提交的pnpm-lock.yaml与仓库根工作区解耦互不污染依赖图它同时被排除在仓库根工作区之外并从根 Nx graph 中被.nxignore忽略——根 Nx 不知道这个子项目的存在避免两个 graph 相互干扰本地nx/*包通过link:依赖接入详见下一节。三、link: 依赖跨工作区边界的本地包接入这是整个示例最关键的一环。package.json 的devDependencies中可以看到devDependencies: { nx/eslint-plugin: link:../../../packages/eslint-plugin, nx/js: link:../../../packages/js, nx/oxlint: link:../../../packages/oxlint, nx/playwright: link:../../../packages/playwright, nx/react: link:../../../packages/react, nx/vite: link:../../../packages/vite, nx: link:../../../packages/nx, ... }原理拆解pnpm 的link:协议允许目录指向工作区之外——../../../packages/*从本目录出发正好落到仓库根下的packages/pnpm 安装时会为这些条目创建指向本地源码目录的符号链接因此node_modules/nx/vite实际就是packages/vite本身由于nx本体同样来自link:../../../packages/nx本工作区执行的nx命令就是当前仓库的本地构建而不是发布版本目录的 nx.json 注册插件后插件解析从本工作区的node_modules出发于是找到的是本地插件构建产物——target 推断与运行时辅助函数全部来自本地代码。需要特别注意编辑本地packages/*源码不会自动触发重建因为本工作区的 Nx graph 看不到仓库根下的这些包。修改插件源码后需要手动重跑 postinstall见第五节。四、插件注册与 Target 推断nx.json 是本工作区的 Nx 配置核心{ $schema: ../../../node_modules/nx/schemas/nx-schema.json, namedInputs: { default: [{projectRoot}/**/*, sharedGlobals], production: [ default, !{projectRoot}/**/?(*.)(spec|test).[jt]s?(x)?(.snap), !{projectRoot}/tsconfig.spec.json, !{projectRoot}/.oxlintrc.json ], sharedGlobals: [] }, plugins: [ nx/vite/plugin, nx/vitest, nx/playwright/plugin, nx/oxlint ], analytics: false, neverConnectToCloud: true }plugins数组是 target 推断的源头。所有 target 都不是手写在project.json里的而是插件基于项目文件结构动态推断出来的Target由哪个插件推断具体行为buildnx/vite/plugin执行vite build产物输出到dist/servenx/vite/plugin启动 Vite dev server端口 4301previewnx/vite/plugin预览生产构建产物testnx/vitest运行 Vitest 单元测试e2enx/playwright/plugin运行 Playwright 端到端测试lintnx/eslint/plugin/nx/oxlint对项目做静态检查从仓库源码看nx/playwright/plugin的推断逻辑实现在 packages/playwright/src/plugins/plugin.ts通过createNodesV2创建 e2e target配套的 packages/playwright/src/plugins/plugin.spec.ts 用大量用例验证了 target 推断、命令行解析与 dependsOn 推导等行为——本示例正是这些推断逻辑的活体测试。此外namedInputs中的production输入把*.spec/test文件、tsconfig.spec.json与.oxlintrc.json排除在生产输入之外保证缓存计算只依赖真正影响产物源码。五、一条命令完成安装postinstall 自动构建链这是示例最精妙的设计——全新 clone 后只需pnpm install即可获得可运行环境。其机制是 package.json 中的 postinstall 钩子scripts: { postinstall: cd ../../.. pnpm nx run-many -t build -p nx js vite react playwright nx/oxlint eslint-plugin, validate: nx run-many -t lint,test,build,e2e }执行顺序pnpm install先完成依赖安装与link:符号链接创建随后 postinstall 回到仓库根目录cd ../../..用根工作区的 Nx 对本地包批量构建nx run-many -t build -p nx js vite react playwright nx/oxlint eslint-plugin构建完成后本工作区的node_modules符号链接立即指向新鲜构建的本地包。validate脚本则是全量验证入口nx run-many -t lint,test,build,e2e一次性跑完所有阶段适合 CI 或提交前自查。日常使用时的常用命令在本目录内执行pnpm install # 安装依赖并触发本地插件构建 nx build # Vite 生产构建 → dist/ nx test # Vitest 单元测试 nx serve # 开发服务器端口 4301 nx e2e # Playwright 端到端测试 nx lint # 静态检查Playwright 首次运行前需要安装浏览器npx playwright install chromium。六、关键配置文件逐项解读6.1 vite.config.mtsVite 与 Vitest 一体化vite.config.mts 在同一份配置里同时承载构建与测试export default defineConfig(() ({ root: import.meta.dirname, cacheDir: ../../../node_modules/.vite/examples/react/basic, server: { port: 4301, host: localhost, }, preview: { port: 4300, host: localhost, }, plugins: [react()], build: { outDir: ./dist, emptyOutDir: true, reportCompressedSize: true, commonjsOptions: { transformMixedEsModules: true, }, }, test: { name: examples-react-basic, watch: false, globals: true, environment: jsdom, include: [{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}], reporters: [default], coverage: { reportsDirectory: ./test-output/vitest/coverage, provider: v8 as const, }, }, }));要点cacheDir指向仓库根node_modules/.vite与根工作区共享缓存目录但按示例名隔离子目录server.port: 4301对应 README 中 serve target 的端口test块即 Vitest 配置jsdom环境 globals: true 对src/tests下*.{test,spec}.*的匹配规则覆盖 v8 报告输出到test-output/vitest/coverage注意vite.config.mts顶部/// reference typesvitest /使 Vitest 的test配置获得类型提示。6.2 playwright.config.tsnxE2EPreset 消费本地预设playwright.config.ts 展示了如何用本地nx/playwright提供的预设驱动 E2Eimport { defineConfig, devices } from playwright/test; import { nxE2EPreset } from nx/playwright/preset; import { workspaceRoot } from nx/devkit; const baseURL process.env[BASE_URL] || http://localhost:4200; export default defineConfig({ ...nxE2EPreset(__filename, { testDir: ./e2e }), use: { baseURL, trace: on-first-retry, }, webServer: { command: npx nx run examples-react-basic:serve, url: baseURL, reuseExistingServer: true, cwd: __dirname, }, projects: [ { name: chromium, use: { ...devices[Desktop Chrome] } }, // 可取消注释以启用 Firefox / WebKit ], });几个值得注意的实现细节nxE2EPreset定义在 packages/playwright/src/utils/preset.ts它接收pathToConfig本示例是手写的 CJS 风格.ts配置因此传__filename自动派生测试报告与结果输出目录当在 CI 中process.env.CI且 Playwright 版本满足要求时会自动追加blobreporter 用于产物合并webServer.command使用npx nx run examples-react-basic:serve而非直接vite这样nx/playwright/plugin可以从命令行推断出dependsOne2e 依赖 serveNx 会先启动开发服务器再跑测试BASE_URL语义配置注释明确说明回退值http://localhost:4200并非 serve 端口serve 在 4301测试只有配合 e2e task env 文件中设置的正确地址才会通过——这是示例在刻意演练通过 Nx 注入环境变量这一能力trace: on-first-retry在测试失败重试时自动收集 trace便于排障。6.3 测试用例单元与端到端的断言单元测试 src/app/app.spec.tsx 基于 Testing Library jsdom验证组件渲染与欢迎文案describe(App, () { it(should render successfully, () { const { baseElement } render(App /); expect(baseElement).toBeTruthy(); }); it(should have a welcome message, () { const { getByText } render(App /); expect(getByText(/Welcome examples-react-basic/i)).toBeTruthy(); }); });E2E 测试 e2e/app.spec.ts 在真实浏览器中导航到/并断言h1内容包含 Welcometest(has welcome heading, async ({ page }) { await page.goto(/); expect(await page.locator(h1).innerText()).toContain(Welcome); });七、修改本地插件后的重建注意点由于本工作区的 Nx graph看不到仓库根的packages/*编辑插件源码不会触发任何自动重构建。README 明确给出两条补救路径二选一# 路径一在本目录重跑 postinstall会回到仓库根构建本地包 pnpm install # 路径二直接在仓库根执行批量构建 pnpm nx run-many -t build -p vite react playwright eslint eslint-plugin这一约束其实是 Dogfood 工程刻意保留的真实现状——它如实暴露了本地插件开发者在迭代时必经的构建环节也让 CI 能够以最朴素的方式验证源码变更 → 构建 → 示例消费全链路。八、小结它为什么值得作为模板examples/react/basic以约二十个文件浓缩了 Nx 工作区的三个核心机制独立 pnpm 工作区 link:依赖用 pnpm 原生的跨工作区符号链接把本地未发布的插件伪装成普通依赖无需任何发布流程插件驱动的 target 推断所有 target 来自nx.json中注册的插件Vite/Vitest/Playwright/Oxlint项目本身零project.json手写 targetpostinstall 自动构建链让全新 clone → 一键可跑可测成为可能pnpm install一步打通。对于任何维护自有 Nx 插件、或希望复用 Nx 插件机制的团队这份示例都是一份高信噪比的参考实现源码、配置与测试彼此印证packages/playwright/src/plugins/plugin.ts、packages/playwright/src/plugins/plugin.spec.ts 与 packages/playwright/src/utils/preset.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),仅供参考