如何为Angular独立组件的模块导入进行排序?
实现Angular独立组件@Component imports数组的分组排序
要让Angular独立组件@Component装饰器内的imports数组,遵循和文件顶部导入一致的分组+字母排序规则,以下是几个可行方案:
方案1:自定义ESLint规则
现有import/order规则仅处理文件顶部的import语句,要覆盖@Component内的数组,需要自定义ESLint规则来解析组件元数据并复用你的分组逻辑:
- 利用
@typescript-eslint/parser解析TypeScript AST,定位到@Component装饰器的配置对象 - 提取其中的
imports数组元素,按照你在import/order里定义的分组(比如外部库、内部模块、相对路径等)归类 - 每组内按模块名字母排序,最后生成自动修复方案替换原数组
核心逻辑示例
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils'; const createRule = ESLintUtils.RuleCreator(() => ''); export default createRule({ name: 'component-imports-order', meta: { type: 'layout', docs: { description: 'Enforce grouping and alphabetical order for @Component imports' }, fixable: 'code', schema: [], }, defaultOptions: [], create(context) { return { 'CallExpression[callee.property.name="Component"] ObjectExpression'(node: TSESTree.ObjectExpression) { // 定位到imports属性 const importsProp = node.properties.find( prop => prop.type === 'Property' && (prop.key as TSESTree.Identifier).name === 'imports' ) as TSESTree.Property | undefined; if (!importsProp || importsProp.value.type !== 'ArrayExpression') return; const importsElements = importsProp.value.elements.filter(el => el !== null) as TSESTree.Expression[]; // 按你的分组规则归类 const groups = { external: [], internal: [], relative: [] }; importsElements.forEach(el => { const moduleName = extractModuleName(el); if (moduleName.startsWith('@angular/')) groups.external.push(el); else if (moduleName.startsWith('@your-org/')) groups.internal.push(el); else if (moduleName.startsWith('./')) groups.relative.push(el); else groups.external.push(el); }); // 每组内按字母排序 const sortedImports = [ ...sortElements(groups.external), ...sortElements(groups.internal), ...sortElements(groups.relative) ]; // 对比原数组,不一致则修复 if (!isArraysEqual(importsElements, sortedImports)) { context.report({ node: importsProp.value, message: 'Component imports must follow grouping and alphabetical order', fix: fixer => fixer.replaceText( importsProp.value, `[${sortedImports.map(el => context.getSourceCode().getText(el)).join(', ')}]` ) }); } } }; // 辅助函数:提取模块名称 function extractModuleName(el: TSESTree.Expression): string { if (el.type === 'Identifier') return el.name; if (el.type === 'CallExpression' && el.callee.type === 'Identifier' && el.callee.name === 'import') { const arg = el.arguments[0]; return arg.type === 'Literal' ? String(arg.value) : ''; } return ''; } // 辅助函数:按模块名排序元素 function sortElements(elements: TSESTree.Expression[]): TSESTree.Expression[] { return elements.sort((a, b) => { const nameA = extractModuleName(a); const nameB = extractModuleName(b); return nameA.localeCompare(nameB); }); } // 辅助函数:对比数组是否一致 function isArraysEqual(a: TSESTree.Expression[], b: TSESTree.Expression[]): boolean { if (a.length !== b.length) return false; return a.every((el, idx) => context.getSourceCode().getText(el) === context.getSourceCode().getText(b[idx])); } } });
将这个规则添加到你的ESLint配置中即可启用:
{ "rules": { "@your-org/component-imports-order": "error" } }
方案2:扩展Angular ESLint插件规则
官方@angular-eslint/eslint-plugin暂无直接支持该需求的规则,但可以参考@angular-eslint/template/order的实现思路,基于现有规则扩展出针对组件元数据imports的排序逻辑,适配你已有的分组配置。
方案3:Prettier插件(简单场景)
如果仅需要字母排序、无需复杂分组,可以使用prettier-plugin-sort-arrays插件,通过配置指定要排序的数组路径(比如["Component.imports"]),实现自动排序,但这种方式无法支持自定义分组逻辑。
内容的提问来源于stack exchange,提问作者Adrien
相关产品推荐
相关产品推荐

