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

发布时间:2026/9/12 16:30:52

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/9/12 17:25:55

厘清三大渠道 AI 采信层级,解密官网成为 AI 核心信源的底层逻辑

大量企业在布局 AI 营销、内容投放时,混淆企业官网、外部媒体资讯、自有自媒体的信息采信定位,盲目投放自媒体短视频、外部付费软文,投入大量预算却无法获得 AI 引用流量。本文从大模型 RAG 检索机制、E-E-A-T 信任评分、实体图谱构建三大技术…

2026/9/12 17:25:55

AMD GPU 运行 CUDA 应用,ZLUDA 要几步?

AMD GPU 运行 CUDA 应用,ZLUDA 要几步? 【免费下载链接】ZLUDA CUDA on non-NVIDIA GPUs 项目地址: https://gitcode.com/GitHub_Trending/zl/ZLUDA 多数 CUDA 应用在启动时会先找英伟达驱动,找不到就直接退出。ZLUDA 补上了这个位置&…

2026/9/12 17:25:55

TradingAgents-CN:让一群 AI 分工完成你的股票研究

TradingAgents-CN:让一群 AI 分工完成你的股票研究 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN TradingAgents-CN 是一个基于大模…

2026/9/12 17:25:55

基于Ollama与Gradio的轻量级本地聊天机器人开发指南

1. 项目概述:基于Ollama与Gradio的轻量级聊天机器人最近在折腾一个很有意思的小项目——用Ollama本地部署大语言模型,再通过Gradio快速搭建聊天界面。整个过程就像搭积木一样简单,不到50行代码就能实现一个功能完整的对话助手。特别适合需要快…

2026/9/12 17:25:55

Nanobrowser 快速教程:三步让 AI 替你操作浏览器

Nanobrowser 快速教程:三步让 AI 替你操作浏览器 【免费下载链接】nanobrowser Open-Source Chrome extension for AI-powered web automation. Run multi-agent workflows using your own LLM API key. Alternative to OpenAI Operator. 项目地址: https://gitco…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

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

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

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