如何使用Angular Schematics修改NgModule模块内的公共变量
你要修改自定义顶层数组变量EXAMPLES的内容,没法直接用addImportToModule这类专门操作NgModule元数据的内置工具,需要基于Schematics提供的AST工具自行实现,具体操作如下:
核心实现步骤
- 导入依赖
直接使用Schematics内置的AST工具即可,无需额外安装依赖:
- 导入依赖
import { Rule, Tree, SchematicsException } from '@angular-devkit/schematics'; import * as ts from 'typescript'; import { insertImport } from '@schematics/angular/utility/ast-utils'; import { InsertChange } from '@schematics/angular/utility/change';
- 读取目标模块文件并生成AST
首先读取你要修改的模块文件内容,转换成TypeScript AST节点树:
- 读取目标模块文件并生成AST
function modifyExamplesArray( modulePath: string, newComponentName: string, newComponentImportPath: string ): Rule { return (tree: Tree) => { // 读取模块文件 const moduleContent = tree.read(modulePath); if (!moduleContent) { throw new SchematicsException(`文件${modulePath}不存在`); } const sourceText = moduleContent.toString('utf-8'); const sourceFile = ts.createSourceFile( modulePath, sourceText, ts.ScriptTarget.Latest, true );
- 查找EXAMPLES数组节点
遍历AST找到顶层的EXAMPLES变量对应的数组表达式节点:
- 查找EXAMPLES数组节点
// 查找EXAMPLES变量声明 let examplesArrayNode: ts.ArrayLiteralExpression | null = null; for (const node of sourceFile.statements) { if (ts.isVariableStatement(node)) { const declaration = node.declarationList.declarations[0]; if ( declaration.name.getText() === 'EXAMPLES' && ts.isArrayLiteralExpression(declaration.initializer) ) { examplesArrayNode = declaration.initializer; break; } } } if (!examplesArrayNode) { throw new SchematicsException(`文件${modulePath}中未找到EXAMPLES数组`); }
- 插入新组件到EXAMPLES数组
调用工具方法往数组最后插入新的组件名,自动兼容空数组、带元素数组的格式:
- 插入新组件到EXAMPLES数组
// 插入新组件到数组 const elements = examplesArrayNode.elements; let insertText = ''; let insertPos = 0; if (elements.length === 0) { // 空数组场景 insertPos = examplesArrayNode.getStart() + 1; insertText = `\n ${newComponentName}\n`; } else { // 已有元素场景 insertPos = elements[elements.length - 1].getEnd(); insertText = `,\n ${newComponentName}`; } const arrayChange = new InsertChange(modulePath, insertPos, insertText);
- 插入新组件的import语句
用内置的insertImport方法添加组件导入,自动处理重复导入判断:
- 插入新组件的import语句
// 插入导入语句 const importChange = insertImport( sourceFile, modulePath, newComponentName, newComponentImportPath ) as InsertChange;
- 将修改应用到文件树
把所有变更写入到Tree中返回即可:
- 将修改应用到文件树
// 应用所有修改 const recorder = tree.beginUpdate(modulePath); recorder.insertLeft(arrayChange.pos, arrayChange.toAdd); recorder.insertLeft(importChange.pos, importChange.toAdd); tree.commitUpdate(recorder); return tree; }; }
注意事项
- 如果你的EXAMPLES数组的缩进不是4个空格,需要对应调整插入文本的缩进量,避免生成格式混乱的代码
- 可以根据需要扩展逻辑,比如先判断组件是否已经在数组中存在,避免重复插入
- 该方法兼容空数组、单元素数组、多元素数组三种场景
内容的提问来源于stack exchange,提问作者injoker1
相关产品推荐
相关产品推荐

