
Nx 23.0 迁移指南将nx/remix插件的createNodesV2导入重命名为createNodes【免费下载链接】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 工作区中使用了nx/remix插件推断功能inferred plugin的开发者讲解 Nx 23.0 引入的自动化迁移把nx/remix/plugin的主导出createNodesV2重命名为规范的createNodes并保留旧的createNodesV2作为已弃用别名。读完本文你将掌握这条迁移的完整行为边界会重写什么、明确跳过什么、其源码级实现原理基于 TypeScript AST 的文本重写机制以及如何通过nx migrate在真实工作区中落地该变更。迁移背景为什么createNodesV2要改名Nx 的插件体系通过「推断插件」在无需手写project.json的情况下从文件系统自动发现项目并推断出 targets。nx/remix作为 Remix 官方集成插件其主推断导出此前命名为createNodesV2。在 Nx 23.0.0 中nx/remix将这一主导出更名为createNodes使之与 Nx 生态其他插件的命名保持一致。createNodesV2这个名字作为已弃用别名暂时保留但新代码应当统一使用createNodes。从源码可以确认这一「同一函数、两个名字」的实现方式packages/remix/src/plugins/plugin.ts 中createNodes是真正的推断插件实现匹配**/{remix,vite}.config.{js,cjs,mjs,ts,cts,mts}配置文件并生成build、dev、start、serve-static、typecheck等 target而紧随其后的export const createNodesV2 createNodes;只是对同一对象的别名引用。公共入口 packages/remix/plugin.ts 同时导出createNodes与createNodesV2因此在运行时两者完全等价任何通过旧名字进行的调用包括命名空间访问、动态导入等都继续可用。正因二者是同一引用这次变更本质上是「更名」而非「替换实现」所以迁移工具可以放心地把createNodesV2的全部静态命名导入重写为createNodes而不会产生行为差异。迁移的行为范围会被重写的内容该迁移由 packages/remix/migrations.json 注册generator 名为update-23-0-0-migrate-create-nodes-v2-import对应版本23.0.0-beta.24实现位于 packages/remix/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.ts。扫描范围迁移会遍历工作区中所有未被忽略的文件但只处理以下四种 TypeScript 扩展名.ts.tsx.cts.mts对每个文件先做一次快速文本检查是否包含createNodesV2不包含则直接跳过避免不必要的解析开销见 migrate-create-nodes-v2-to-create-nodes.ts#L39-L52。测试用例也验证了非 TS 文件如docs/example.md不会被改动。唯一命中的模块说明符只有从nx/remix/plugin导入或再导出的createNodesV2才会被重写TARGET_SPECIFIERS集合中目前只有这一项。以下来源的createNodesV2不会被触碰来自其他模块如import { createNodesV2 } from nx/other-plugin/plugin;来自相对路径如import { createNodesV2 } from ./plugin;这两条边界均有对应单元测试覆盖见 migrate-create-nodes-v2-to-create-nodes.spec.ts#L103-L116。具体的改写规则1. 普通命名导入// Before import { createNodesV2 } from nx/remix/plugin; // After import { createNodes } from nx/remix/plugin;2. 混合命名导入其他导出保持不动仅重命名createNodesV2// Before import { createNodesV2, SomeOtherExport } from nx/remix/plugin; // After import { createNodes, SomeOtherExport } from nx/remix/plugin;3. 别名导入别名本地绑定名保留只重写「原导出名」一侧// Before import { createNodesV2 as cn } from nx/remix/plugin; // After import { createNodes as cn } from nx/remix/plugin;4. 冗余别名折叠createNodesV2 as createNodes会被折叠为单个createNodes// Before import { createNodesV2 as createNodes } from nx/remix/plugin; // After import { createNodes } from nx/remix/plugin;5. 重复绑定去重若同一文件同时导入了createNodes与createNodesV2无论先后顺序冗余绑定都会被删除// Before import { createNodes, createNodesV2 } from nx/remix/plugin; // After import { createNodes } from nx/remix/plugin;多行命名导入同样会被重排为单行形式见 spec#L61-L66。6. 默认导入与 type 导入默认导入保留import type、内联type修饰符也被正确保留// Before import def, { createNodesV2 } from nx/remix/plugin; import type { createNodesV2 } from nx/remix/plugin; import { type createNodesV2 } from nx/remix/plugin; // After import def, { createNodes } from nx/remix/plugin; import type { createNodes } from nx/remix/plugin; import { type createNodes } from nx/remix/plugin;7. 命名再导出export { ... } from nx/remix/plugin与导入同样处理别名规则一致// Before export { createNodesV2 } from nx/remix/plugin; export { createNodesV2 as cn } from nx/remix/plugin; // After export { createNodes } from nx/remix/plugin; export { createNodes as cn } from nx/remix/plugin;8. 文件体内对绑定名的值引用当一个本地绑定确实被重命名无别名的{ createNodesV2 }或被去重合并进已有createNodes时文件体内所有对该绑定的值引用也会同步重写否则会留下悬空引用。测试覆盖了变量赋值、函数调用实参如addPlugin(graph, nx/remix/plugin, createNodesV2, {})、对象简写属性等场景// Before import { createNodesV2 } from nx/remix/plugin; export const plugin createNodesV2; // After import { createNodes } from nx/remix/plugin; export const plugin createNodes;9. 对象简写属性的展开{ createNodesV2 }简写会被展开为{ createNodesV2: createNodes }从而保留属性键名// Before import { createNodesV2 } from nx/remix/plugin; export const plugins { createNodesV2 }; // After import { createNodes } from nx/remix/plugin; export const plugins { createNodesV2: createNodes };不会被重写的内容及原因这是本次迁移最关键的行为边界。以下形式的createNodesV2全部保持原样因为它们不依赖静态命名绑定且能通过运行时别名继续正常工作命名空间导入import * as plugin from nx/remix/plugin后通过plugin.createNodesV2访问动态导入import(nx/remix/plugin)之后解构CommonJS 解构const { createNodesV2 } require(nx/remix/plugin);有专门测试验证其保持不变属性访问 / 限定类型名config.createNodesV2、PluginTypes.createNodesV2export * from再导出export * from nx/remix/plugin;没有可重命名的具名绑定对象字面量键{ createNodesV2: something }中的键名不是绑定引用遮蔽声明文件中若存在名为createNodesV2的变量、参数或函数声明属于遮蔽shadowing不会被误改字符串与注释createNodesV2、// import { createNodesV2 } ...一律不动。对于这些形式若你希望彻底移除弃用名字需要手工更新。由于createNodesV2只是运行时别名即使不改代码依然正常工作相关边界判定逻辑见 migrate-create-nodes-v2-to-create-nodes.ts#L280-L316。迁移的源码实现原理实现 migrate-create-nodes-v2-to-create-nodes.ts 的机制值得了解便于理解上述所有行为整体流程入口migrateCreateNodesV2ToCreateNodes(tree)通过visitNotIgnoredFiles遍历工作区过滤出 TS 扩展名文件做createNodesV2文本预检命中后调用核心函数rewriteCreateNodesV2Imports若有文件实际发生变化通过logger.info输出改动文件数最后调用formatFiles统一格式化。累计改动文件数统计逻辑见 migrate-create-nodes-v2-to-create-nodes.ts#L34-L61。AST 解析rewriteCreateNodesV2Imports使用typescript的createSourceFile将源码解析为 ASTScriptKind.TSX遍历顶层语句区分ImportDeclaration与ExportDeclaration分别处理。字符串补丁而非整文件重写核心的rewriteNamedBindings会重新渲染{ ... }绑定列表——重命名createNodesV2为createNodes、丢弃重复项、保留每个绑定上的type修饰符与别名——然后通过applyChangesToString以「删除旧区间 插入新文本」的方式生成补丁见 migrate-create-nodes-v2-to-create-nodes.ts#L173-L212。这意味着模块说明符、import/export关键字、默认导入、type修饰符等周边内容全部原样保留只动绑定列表本身。条件性的值引用重写只有当本地绑定名真正发生变化无别名导入或被去重时才会触发collectValueUsageRewrites重写文件体内的标识符引用并配合isRenamableValueUsage排除属性访问、限定名、对象键、遮蔽声明等不可重写的语法位置。如何在你的工作区执行这条迁移nx/remix的迁移注册于 packages/remix/migrations.json由 Nx 迁移机制统一驱动。在升级到 Nx 23 时升级 Nx 相关依赖到 23.x该迁移对应的version字段为23.0.0-beta.24在仓库根目录运行迁移命令Nx 会读取各插件的migrations.json并自动应用update-23-0-0-migrate-create-nodes-v2-importnx migrate nx/remix按 Nx 常规流程先nx migrate更新 package.json 并安装依赖再运行nx migrate --run-migrations执行迁移文件。迁移完成后检查migrations.json生成的迁移文件输出日志Renamed \createNodesV2 imports to createNodes in N file(s).并在各应用/库下运行类型检查与测试确认无悬空引用。迁移后的代码该长什么样迁移完成后你的推断插件注册代码应使用规范名。例如一个手写插件配置或入口文件应呈现为import { createNodes } from nx/remix/plugin; // 在 nx.json / 插件配置中使用 createNodes export default { name: nx/remix/plugin, createNodes, options: { buildTargetName: build, devTargetName: dev, startTargetName: start, typecheckTargetName: typecheck, serveStaticTargetName: serve-static, }, };同时仓库内部源码也已全面转向新命名可作为「迁移后的正确写法」的参考nx/remix自己的生成器在注册插件时使用createNodesV2因为内部运行时别名仍存在见 init.ts#L11、convert-to-inferred.ts#L7而插件入口 packages/remix/plugin.ts 同时导出两个名字其中createNodes已排在首位。常见问题Q迁移后nx命令还能识别旧的createNodesV2吗能。createNodesV2作为已弃用别名保留export const createNodesV2 createNodes;运行时行为完全一致只是新代码不应再使用。Q为什么我的require(nx/remix/plugin)没被改迁移只重写静态import/export的具名绑定。require解构、命名空间访问、动态import()等通过运行时别名继续工作不在自动重写范围内需要的话请手工更新。Q迁移会不会误改其他包导出的同名符号不会。TARGET_SPECIFIERS只匹配nx/remix/plugin来自其他模块或相对路径的createNodesV2一律跳过。Q如果我同时导入了createNodes和createNodesV2会怎样冗余绑定会被自动删除只保留createNodes且文件体内引用同步更新。【免费下载链接】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),仅供参考