尧图精选

Nx 23 迁移:`ensure-vitest-package-migration` 如何将 Vitest 从 `@nx/vite` 平滑迁移到 `@nx/vitest`

🕒 发布时间:2026/9/12 3:10:03 📁 来源:尧图网络
Nx 23 迁移ensure-vitest-package-migration如何将 Vitest 从nx/vite平滑迁移到nx/vitest【免费下载链接】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 23 中随nx migrate自动运行的ensure-vitest-package-migration迁移机制。自 Nx 23 起原先寄居于nx/vite包中的 Vitest 能力nx/vite:testexecutor、nx/vite:vitestgenerator、以及nx/vite/plugin中的测试目标推断被整体移除改由独立的nx/vitest包独家提供。本文以仓库中该迁移的文档、实现源码与完整测试用例为依据详细讲解其自动执行的四项工作、底层判断逻辑、典型场景下的前后配置变化以及升级后如何验证迁移结果帮助你理解并掌控这条安全网迁移路径。迁移背景Vitest 为什么从nx/vite中独立出来在 Nx 22 及更早版本中Vitest 支持是nx/vite包的一部分。工作区通过以下方式使用 Vitest在project.json的 target 中使用nx/vite:testexecutor使用nx/vite:vitestgenerator 生成测试配置依赖nx/vite/plugin的插件推断自动生成 vitest 测试目标。到了 Nx 23这些能力被全部移除并迁移至全新的packages/vitest包。该包的定位在package.json中写得很明确The Nx Plugin for Vitest to enable fast unit testing with Vitest其 peerDependencies 声明支持vitest: ^3.0.0 || ^4.0.0与vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0。Nx 官方为这条破坏性变更设计了两段式迁移路径可选迁移v22migrate-vitest-to-vitest-package对应packages/vite/src/migrations/update-22-2-0/migrate-vitest-to-vitest-package.ts负责将 Vitest 使用迁移到nx/vitest包。兜底安全网v23本文的主角ensure-vitest-package-migration在nx migrate升级到 Nx 23 时自动运行专门处理那些跳过了可选迁移、或迁移后仍残留nx/viteVitest 痕迹的工作区。二者的注册信息都位于 packages/vite/migrations.jsonmigrate-vitest-to-vitest-package: { version: 22.2.0-beta.2, description: Migrate Vitest usage from nx/vite to nx/vitest package., implementation: ./dist/src/migrations/update-22-2-0/migrate-vitest-to-vitest-package }, ensure-vitest-package-migration-23: { version: 23.0.0-beta.10, description: Safety net: ensure any remaining nx/vite:test executor usages are swapped to nx/vitest:test and nx/vitest is installed., implementation: ./dist/src/migrations/update-23-0-0/ensure-vitest-package-migration, documentation: ./dist/src/migrations/update-23-0-0/ensure-vitest-package-migration.md }注意ensure-vitest-package-migration-23的 description 明确将其定位为 Safety net安全网这解释了它存在的意义不是替代 v22 迁移而是保证任何工作区升级到 Nx 23 后都不会出现测试目标静默丢失的断崖。迁移做了什么四项自动操作迁移的入口函数位于 ensure-vitest-package-migration.ts其执行流程清晰划分为四个步骤const migratedExecutors migrateExecutorUsages(tree); const migratedPlugins migratePluginConfigurations(tree); const migratedTargetDefaults migrateTargetDefaults(tree); const registeredVitestPlugin await ensureVitestPluginRegistration(tree); if (migratedExecutors || migratedPlugins || migratedTargetDefaults || registeredVitestPlugin) { const installTask installVitestPackage(tree); await formatFiles(tree); return installTask; } else { return () {}; }以下逐一展开每一项的具体行为与触发条件。1. 安装nx/vitest到 devDependencies当检测到工作区确实在使用 Vitest、且尚未安装nx/vitest时迁移会将其以nxVersion即当前nx/vite包版本见 packages/vite/src/utils/versions.ts写入package.json的devDependencies。实现位于installVitestPackage函数function installVitestPackage(tree: Tree): GeneratorCallback { const packageJson readJson(tree, package.json); const hasNxVitest packageJson.dependencies?.[nx/vitest] || packageJson.devDependencies?.[nx/vitest]; if (hasNxVitest) { return () {}; } return addDependenciesToPackageJson(tree, {}, { nx/vitest: nxVersion }); }关键行为细节幂等如果dependencies或devDependencies中已存在nx/vitest直接跳过安装不会覆盖或升级既有版本条件安装只有迁移四项中的任何一项实际发生了变化才会触发安装由主入口的if分支控制纯 Vite 构建场景不会被强行引入nx/vitest。2. 将nx/vite:testexecutor 替换为nx/vitest:testmigrateExecutorUsages使用forEachExecutorOptions遍历整个工作区收集所有仍在project.json的 target 中使用nx/vite:testexecutor 的项目然后将 executor 字段改写为nx/vitest:testforEachExecutorOptions(tree, nx/vite:test, (_options, projectName) { projectsToUpdate.add(projectName); }); // ... for (const target of Object.values(projectConfig.targets ?? {})) { if (target.executor nx/vite:test) { target.executor nx/vitest:test; } } updateProjectConfiguration(tree, projectName, projectConfig);这一点有测试直接验证见 ensure-vitest-package-migration.spec.ts配置了executor: nx/vite:test且带options.configFile的 target迁移后 executor 变为nx/vitest:test而options原样保留。也就是说只改 executor 标识不动任何既有选项configFile、watch、testFiles等原有配置全部兼容。典型的迁移前后对比// 迁移前 project.json { targets: { test: { executor: nx/vite:test, options: { configFile: libs/my-lib/vite.config.ts } } } } // 迁移后 project.json { targets: { test: { executor: nx/vitest:test, options: { configFile: libs/my-lib/vite.config.ts } } } }3. 拆分nx/vite/plugin注册Vitest 选项归 VitestVite 选项归 VitemigratePluginConfigurations遍历nx.json中plugins数组的每一个nx/vite/plugin条目将其 options 中与测试相关的三个字段——testTargetName、ciTargetName、ciGroupName——抽取出来生成一个新的nx/vitest插件条目原nx/vite/plugin条目则只保留 build/serve/preview 相关选项const { testTargetName, ciTargetName, ciGroupName, ...viteOptions } options; if (!testTargetName !ciTargetName !ciGroupName) { newPlugins.push(plugin); // 没有测试选项原样保留 continue; } const vitestPlugin: PluginEntry { plugin: nx/vitest }; if (Object.keys(vitestOptions).length 0) { vitestPlugin.options vitestOptions; } if (plugin.include) vitestPlugin.include plugin.include as string[]; if (plugin.exclude) vitestPlugin.exclude plugin.exclude as string[];这一拆分在测试中有完整覆盖见 ensure-vitest-package-migration.spec.ts。迁移前后的nx.json变化如下// 迁移前 { plugins: [ { plugin: nx/vite/plugin, options: { buildTargetName: build, testTargetName: unit-test, ciTargetName: unit-test-ci, ciGroupName: unit-tests }, include: [apps/**/*], exclude: [apps/legacy/*] } ] } // 迁移后 { plugins: [ { plugin: nx/vite/plugin, options: { buildTargetName: build }, include: [apps/**/*], exclude: [apps/legacy/*] }, { plugin: nx/vitest, options: { testTargetName: unit-test, ciTargetName: unit-test-ci, ciGroupName: unit-tests }, include: [apps/**/*], exclude: [apps/legacy/*] } ] }实现要点include/exclude作用域会被镜像到新的nx/vitest条目上保证 vitest 目标推断与原 Vite 插件覆盖相同项目范围若抽取后viteOptions为空options字段会被整体删除而非留下空对象拆分会按include/exclude组合成的作用域scopeKey去重避免重复注册。4. 注册nx/vitest插件默认配置场景的自动补齐这是安全网中最关键、也最容易被忽视的一步。ensureVitestPluginRegistration专门处理用了nx/vite/plugin但没有配置任何 vitest 选项的工作区——即nx.json中以字符串形式注册nx/vite/plugin或注册为{ plugin: nx/vite/plugin }且 options 为空。由于这类裸注册不携带testTargetName等信号第 3 步的拆分逻辑不会为它创建nx/vitest条目。如果不做处理升级后这些项目的 vitest 测试目标推断就会在 Nx 23 中静默丢失。ensureVitestPluginRegistration正是为了堵住这个缺口const vitePluginRegistrations nxJson.plugins.filter((p) typeof p string ? p nx/vite/plugin : p.plugin nx/vite/plugin ); // Only register nx/vitest when the workspace actually uses vitest. if (!(await workspaceUsesVitest(tree))) { return false; }它按作用域include/exclude 组合逐一为裸注册的nx/vite/plugin配对生成对应的nx/vitest条目并通过coveredScopes集合去重避免与第 3 步已拆分出的条目重复。混合形态的配置一个作用域带testTargetName、另一个裸注册也能被正确处理这在测试用例 should pair nx/vitest with each scoped nx/vite/plugin even when one scope already had testTargetName and another was barespec 第 246 行起中有完整覆盖。5. 迁移targetDefaultsexecutor 键与 target 名键双模式migrateTargetDefaults处理nx.json中targetDefaults的两种写法executor 键模式nx/vite:test: { ... }整体重命名为nx/vitest:testtarget 名键模式test: { executor: nx/vite:test, ... }仅将executor字段改为nx/vitest:test。if (targetOrExecutor nx/vite:test) { nxJson.targetDefaults[nx/vitest:test] ?? {}; Object.assign(nxJson.targetDefaults[nx/vitest:test], targetConfig); delete nxJson.targetDefaults[nx/vite:test]; } else if (targetConfig.executor nx/vite:test) { targetConfig.executor nx/vitest:test; }三个行为细节均有测试佐证见 spec 的 migrateTargetDefaults describe 块迁移后nx/vite:test旧键被删除nx/vitest:test继承全部原配置cache、inputs、options等若两个键同时存在旧键值通过Object.assign覆盖新键的重叠字段非重叠字段保留——这是实现注释中明示的对有意配置过旧键的用户更安全的默认行为Array.isArray(targetConfig)的条目会被跳过该迁移早于过滤数组形态的 targetDefaults此处值均为普通对象。何时才真正执行Vitest 使用检测逻辑迁移第 4 步依赖workspaceUsesVitest函数判断工作区是否真的在使用 Vitest源码 L229-L256。该判断按优先级依次检查依赖声明package.json的dependencies或devDependencies中存在vitest配置文件信号通过globAsync扫描**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}任何vitest.config.*文件 → 判定为使用 Vitestvite.config.*中出现顶层的test:键正则/(^|[\s,{])test\s*:/m→ 判定为使用 Vitest。该函数的注释明确说明了一种有意为之的偏置正则可能把注释掉的test:也误判为命中但这种过度安装over-install是安全的——相比漏判真实用法导致推断出的测试目标丢失多装一个包要稳妥得多。只有当工作区使用了 Vitest 时迁移才会注册nx/vitest插件并触发依赖安装纯 Vite 构建的工作区则完全不受影响对应测试见 spec L143-L157 与 L224-L244。升级操作与迁移结果验证执行迁移该迁移是 Nx 迁移链的一部分无需手动干预。在仓库根目录依次运行nx migrate latest随后执行自动生成的迁移脚本Nx 通常会提示具体的 migration runner 命令如nx migrate --run-migrationsmigrations.json迁移即自动完成。原文明确指出运行nx migrate后无需任何手动操作。验证迁移结果迁移完成后重点检查三个文件package.jsondevDependencies中应出现nx/vitest版本与当前 Nx 版本一致nx.jsonplugins中不应再有携带testTargetName/ciTargetName/ciGroupName的nx/vite/plugin条目应存在对应的nx/vitest插件条目包括为裸注册补齐的条目targetDefaults中不应残留nx/vite:test键应被nx/vitest:test替代各project.json所有executor: nx/vite:test均已变为executor: nx/vitest:test且options原样保留。验证测试目标仍可正常推断与运行迁移后vitest 测试目标的发现与运行遵循nx/vitest插件的新规则参见 packages/vitest/PLUGIN.md。该文档给出了两种运行方式模式检测顺序先命中者生效模式检测依据推断Inferencenx.json的plugins数组中存在nx/vitest或nx/vite/plugin执行器Executorproject.json的targets中存在nx/vitest:testexecutor运行指定测试文件# 推断模式 nx test project -- path/to/file.spec.ts # 执行器模式 nx run project:test --testFilepath/to/file.spec.ts常用快捷命令任务推断模式执行器模式运行指定文件nx test proj -- path/file.spec.tsnx run proj:test --testFilepath/file.spec.ts按名称模式运行nx test proj -- -t patternnx run proj:test --testNamePatternpatternnx/vitest包的 executor 注册于 packages/vitest/executors.json即nx/vitest:test。边界情况与行为保证基于源码与测试该迁移具备以下可预期、可验证的行为保证幂等性工作区已注册nx/vitest插件且nx/vite/plugin无测试选项时迁移是纯 no-op不会重复注册spec L159-L172不重复安装nx/vitest已存在时保持原版本不变spec L188-L207只处理相关项目未使用nx/vite/plugin或nx/vite:test的工作区例如仅用nx/eslint/plugin完全不受影响spec L174-L186作用域一致无论哪种迁移路径新生成的nx/vitest条目都继承原nx/vite/plugin的include/exclude保证测试目标推断的覆盖范围与迁移前一致安全优先Vitest 使用检测偏向于过度安装宁可多装nx/vitest也不让依赖推断的测试目标意外丢失。小结ensure-vitest-package-migration是 Nx 23 升级链路中的一道自动安全网它兜底处理了 v22 可选迁移遗漏的所有nx/viteVitest 残留——替换 executor、拆分插件配置、迁移 targetDefaults、按需注册nx/vitest插件并安装依赖。理解它的触发条件、检测逻辑与幂等行为能让你在nx migrate升级后自信地核对package.json、nx.json与各project.json确保 vitest 测试目标在 Nx 23 中无缝延续。参考文件索引迁移文档packages/vite/src/migrations/update-23-0-0/ensure-vitest-package-migration.md迁移实现packages/vite/src/migrations/update-23-0-0/ensure-vitest-package-migration.ts迁移测试packages/vite/src/migrations/update-23-0-0/ensure-vitest-package-migration.spec.ts迁移注册表packages/vite/migrations.json前序 v22 迁移packages/vite/src/migrations/update-22-2-0/migrate-vitest-to-vitest-package.tsnx/vitest包元信息packages/vitest/package.json测试运行指引packages/vitest/PLUGIN.md【免费下载链接】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),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →