创建NX插件时如何兼容多版本并获取项目根目录?
NX插件跨版本兼容(NX14前后)及嵌套项目根目录获取方案
1. 修复NX14前updateProjectConfiguration丢失root键的问题
NX14及以上版本不再使用root字段,但旧版本中updateProjectConfiguration会移除该字段导致配置损坏。解决思路是根据NX版本决定是否保留root:
- 读取当前NX版本,若版本低于14,在更新配置时显式保留原
root值 - 版本判断可直接读取
nx包的版本信息
代码示例:
import { Tree, readProjectConfiguration, updateProjectConfiguration } from '@nrwl/devkit'; export default async function (tree: Tree, options: { project: string }) { const projectConfiguration = readProjectConfiguration(tree, options.project); const nxVersion = require('nx/package.json').version; const isPreNx14 = parseInt(nxVersion.split('.')[0]) < 14; // 构建更新后的配置 const updatedConfig = { ...projectConfiguration, targets: { ...projectConfiguration.targets, myExecutor: { executor: '@package/my-executor', }, }, }; // 旧版本强制保留root字段 if (isPreNx14 && projectConfiguration.root) { updatedConfig.root = projectConfiguration.root; } updateProjectConfiguration(tree, options.project, updatedConfig); }
2. 精准获取嵌套项目根目录
不管NX版本,要正确获取如project-folder-project1-nested这类嵌套项目的根路径(对应/libs/project-folder/project1-nested),可通过以下两种可靠方式:
方式一:优先使用配置中的root, fallback到名称推导
利用NX工具函数判断项目类型(应用/库),结合项目名称拆分路径:
import { getWorkspaceLayout, readProjectConfiguration, joinPathFragments } from '@nrwl/devkit'; // 在生成器函数内添加以下逻辑 const projectConfiguration = readProjectConfiguration(tree, options.project); const workspaceLayout = getWorkspaceLayout(tree); let projectRoot: string; // 旧版本直接用配置中的root if (projectConfiguration.root) { projectRoot = projectConfiguration.root; } else { // 拆分嵌套项目名称:按最后一个连字符分割(适配scope-name命名规则) const [scopeSegment, nameSegment] = options.project.split(/-(?=[^-]+$)/); // 根据项目类型选择apps或libs目录 const baseDir = projectConfiguration.projectType === 'application' ? workspaceLayout.appsDir : workspaceLayout.libsDir; // 拼接最终根路径 projectRoot = joinPathFragments(baseDir, scopeSegment, nameSegment); }
方式二:直接读取项目配置文件(最精准)
对于命名规则特殊的项目,可直接读取项目的project.json文件获取根路径:
import { joinPathFragments } from '@nrwl/devkit'; // 在生成器函数内添加以下逻辑 let projectRoot: string; // 尝试从项目的project.json读取root const possibleProjectJsonPaths = [ joinPathFragments('apps', options.project.replace(/-/g, '/'), 'project.json'), joinPathFragments('libs', options.project.replace(/-/g, '/'), 'project.json') ]; for (const jsonPath of possibleProjectJsonPaths) { if (tree.exists(jsonPath)) { const projectJson = JSON.parse(tree.read(jsonPath).toString()); projectRoot = projectJson.root ?? jsonPath.split('/project.json')[0]; break; } } // 兜底:如果没找到,用名称推导 if (!projectRoot) { const workspaceLayout = getWorkspaceLayout(tree); const baseDir = projectConfiguration.projectType === 'application' ? workspaceLayout.appsDir : workspaceLayout.libsDir; projectRoot = joinPathFragments(baseDir, options.project.replace(/-/g, '/')); }
完整兼容代码
将上述逻辑整合后的完整生成器代码:
import { Tree, readProjectConfiguration, updateProjectConfiguration, getWorkspaceLayout, joinPathFragments, generateFiles } from '@nrwl/devkit'; import * as path from 'path'; export default async function (tree: Tree, options: { project: string }) { const projectConfiguration = readProjectConfiguration(tree, options.project); const workspaceLayout = getWorkspaceLayout(tree); const nxVersion = require('nx/package.json').version; const isPreNx14 = parseInt(nxVersion.split('.')[0]) < 14; // 更新项目配置,兼容NX14前后 const updatedConfig = { ...projectConfiguration, targets: { ...projectConfiguration.targets, myExecutor: { executor: '@package/my-executor', }, }, }; if (isPreNx14 && projectConfiguration.root) { updatedConfig.root = projectConfiguration.root; } updateProjectConfiguration(tree, options.project, updatedConfig); // 获取项目根目录 let projectRoot: string; if (projectConfiguration.root) { projectRoot = projectConfiguration.root; } else { const [scopeSegment, nameSegment] = options.project.split(/-(?=[^-]+$)/); const baseDir = projectConfiguration.projectType === 'application' ? workspaceLayout.appsDir : workspaceLayout.libsDir; projectRoot = joinPathFragments(baseDir, scopeSegment, nameSegment); } // 生成文件到项目根目录 generateFiles(tree, path.join(__dirname, 'files/projectFiles'), projectRoot, { ...fileReplacementOptions }); };
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

