Nx 仓库 Dogfood 实战:examples/react/basic 独立 pnpm 工作区如何用 link: 依赖驱动本地插件端到端验证

发布时间:2026/11/12 6:59:09

Nx 仓库 Dogfood 实战:examples/react/basic 独立 pnpm 工作区如何用 link: 依赖驱动本地插件端到端验证 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),仅供参考
延伸阅读

更多相关文章

2026/11/12 6:54:26

河南漯河施工企业负责人必看!特种作业操作证维修电工中级证怎么考?官方报名入口在哪?

河南漯河施工企业负责人必看!特种作业操作证维修电工中级证怎么考?官方报名入口在哪? 不知道去哪报名怕被中介坑?特别是像你这样在漯河做中小施工企业的负责人,天天和特种作业操作证打交道,稍有不慎就可能被坑一笔,甚至影响项目进度和企业信誉。别急,…

2026/11/12 6:54:26

办理哪里有报考电工证的需要什么材料

电工证哪里有报考的?2026河南最新政策你必须知道 你缺的不是能力,缺的是电工证!现在想找电工相关的工作, 急需特种作业证才能上岗找工作 ,没有证连面试资格都没有。特别是2026年河南最新政策出台后,电工证的报考条件、流程、复审等都有了…

2026/11/12 6:54:26

南宁电工证换证在哪里 电工证上岗必备的复审流程与避坑指南

南宁电工证换证在哪里 电工证上岗必备的复审流程与避坑指南 证书过期了不知道怎么复审延期,是不是你正面临的难题?在南宁,不少电工因为不懂换证流程,导致证书失效,直接失去上岗资格。特别是像周口这样的建筑工地,电工证不仅是 上岗必备…

2026/11/12 6:49:26

电工证会注销不?千万别踩坑,别让证书变成废纸

电工证会注销不?千万别踩坑,别让证书变成废纸 你是不是也遇到过这样的问题: 不知道去哪报名怕被中介坑 ?电工证作为特种作业人员必备的上岗凭证,很多人以为只要考了就一劳永逸,其实不然。 电工证会注销不…

2026/11/11 12:42:59

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/12 0:04:01

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘 工地太忙根本没时间复习考试?你不是一个人。作为一名在南阳卧龙区干了七八年市政公用工程的电工,我深知这个问题的现实性。电工证不仅是工作的“入场券”,更是职业发展的“通行证”,但备考过程…

2026/11/12 0:04:01

双流电工证考别怕挂科!郑州报考避坑指南全攻略

双流电工证考别怕挂科!郑州报考避坑指南全攻略 实操考试心里没底怕挂科?双流电工证考在郑州报名,很多人因为不了解流程、准备不充分,白白浪费时间和金钱。作为三门峡应届工程类毕业生,我也曾经历过这样的焦虑。今天就从零开始,手把手教你如何避开郑州报…

2026/11/12 0:04:01

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少 之前考的证在外省能不能转过来?这个问题确实让不少准备换城市工作的朋友犯了难,尤其像电工证这种实操性很强的证书,很多人担心跨省后证书能不能继续用。其实,只要符合相关流程,是可以顺利转…

2026/11/11 20:27:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/10 10:29:37

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑