Angular 18项目中如何让inline template应用自闭合标签ESLint规则
问题背景
在Angular 18.1项目中,已通过.eslintrc.json配置让独立HTML模板文件(*.html)强制使用自闭合标签,但内联模板(*.ts组件文件中的template字符串)无法应用该规则。尝试在"files": ["*.ts"]的rules字段中添加"@angular-eslint/template/prefer-self-closing-tags": "error"时,ESLint提示需配置@angular-eslint/template-parser作为解析器;若将该解析器添加到extends字段又会出现加载失败错误。原本依赖plugin:@angular-eslint/template/process-inline-templates处理内联模板,但未生效。
项目依赖片段(package.json)
"@angular-devkit/build-angular": "^18.1.1", "@angular-eslint/builder": "18.1.0", "@angular-eslint/eslint-plugin": "18.1.0", "@angular-eslint/eslint-plugin-template": "18.1.0", "@angular-eslint/schematics": "18.1.0", "@angular-eslint/template-parser": "18.1.0", "@angular/cli": "^18.1.1", "@angular/compiler-cli": "^18.1.1",
原.eslintrc.json配置
{ "root": true, "ignorePatterns": ["projects/**/*", "**/*.py", "dev_index.html"], "overrides": [ { "files": ["*.ts"], "parserOptions": { "project": ["./tsconfig.eslint.json"], "createDefaultProgram": true }, "extends": [ "plugin:@typescript-eslint/recommended", "plugin:@angular-eslint/recommended", "plugin:@angular-eslint/template/process-inline-templates", "plugin:prettier/recommended" ], "plugins": ["rxjs"], "rules": { "@typescript-eslint/explicit-function-return-type": [ "off", { "allowExpressions": true } ], "no-await-in-loop": "error", "no-extra-parens": "off", "no-prototype-builtins": "off", "no-template-curly-in-string": "error", "valid-jsdoc": "off", "@typescript-eslint/array-type": [ "off", { "default": "array" } ], "accessor-pairs": "off", "no-unused-vars": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": [ "off", { "vars": "all", "args": "none", "ignoreRestSiblings": true, "caughtErrors": "none", "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" } ], "array-callback-return": "error", "block-scoped-var": "error", "class-methods-use-this": "off", "complexity": "off", "consistent-return": "error", "curly": "error", "default-case": "error", "dot-location": ["error", "property"], "no-console": [ "off", { "allow": ["warn", "error"] } ], "dot-notation": "off", "eqeqeq": "off", "guard-for-in": "off", "no-alert": "off", "no-caller": "error", "no-div-regex": "error", "no-else-return": "off", "no-empty-function": "off", "no-eq-null": "error", "no-eval": "error", "no-extend-native": "error", "no-extra-bind": "error", "no-extra-label": "error", "no-floating-decimal": "error", "no-implicit-coercion": "off", "no-implicit-globals": "error", "no-implied-eval": "error", "no-invalid-this": "off", "no-iterator": "error", "no-labels": "error", "no-lone-blocks": "error", "no-loop-func": "error", "no-magic-numbers": [ "off", { "ignore": [-1, 0, 1], "ignoreArrayIndexes": true } ], "no-multi-spaces": [ "error", { "ignoreEOLComments": true, "exceptions": { "AssignmentExpression": true, "ArrowFunctionExpression": true, "CallExpression": true, "VariableDeclarator": true } } ], "no-multi-str": "error", "no-new": "error", "no-new-func": "off", "no-new-wrappers": "error", "no-octal-escape": "error", "no-param-reassign": "off", "no-proto": "error", "no-restricted-properties": "error", "no-return-assign": "error", "no-return-await": "error", "no-script-url": "error", "no-self-compare": "error", "no-sequences": "error", "no-throw-literal": "error", "no-unmodified-loop-condition": "error", "no-unused-expressions": "off", "no-useless-call": "error", "no-useless-concat": "error", "no-useless-return": "error", "no-void": "error", "no-warning-comments": "off", "no-with": "error", "prefer-promise-reject-errors": "error", "radix": "error", "require-await": "off", "vars-on-top": "off", "wrap-iife": "error", "yoda": "error", "strict": "error", "init-declarations": "off", "no-catch-shadow": "off", "no-label-var": "error", "no-restricted-globals": "error", "no-shadow": "off", "no-shadow-restricted-names": "error", "no-undef-init": "error", "no-undefined": "off", "no-use-before-define": "off", "@angular-eslint/directive-selector": [ "error", { "type": "attribute", "prefix": "app", "style": "camelCase" } ], "@angular-eslint/component-selector": [ "error", { "type": "element", "prefix": "app", "style": "kebab-case" } ], "rxjs/no-unsafe-takeuntil": [ "warn", { "alias": ["takeUntilDestroyed"] } ], "rxjs/no-async-subscribe": ["warn"], "rxjs/no-create": ["warn"], "rxjs/no-index": ["warn"], "rxjs/no-ignored-replay-buffer": ["warn"], "rxjs/no-ignored-takewhile-value": ["warn"], "rxjs/no-internal": ["warn"], "rxjs/no-nested-subscribe": ["warn"], "rxjs/no-redundant-notify": ["warn"], "rxjs/no-subject-unsubscribe": ["warn"], "rxjs/no-unbound-methods": ["warn"], "rxjs/no-unsafe-subject-next": ["warn"] } }, { "files": ["*.html"], "extends": [ "plugin:@angular-eslint/template/recommended", "plugin:prettier/recommended" ], "rules": { "@angular-eslint/template/label-has-associated-control": "off", "@angular-eslint/template/valid-aria": "off", "@angular-eslint/template/alt-text": "error", "@angular-eslint/template/no-autofocus": "off", "@angular-eslint/template/no-distracting-elements": "error", "@angular-eslint/template/use-track-by-function": "off", "@angular-eslint/template/prefer-self-closing-tags": "error" } }, { "files": ["*.html"], "excludedFiles": ["*inline-template-*.component.html"], "extends": ["plugin:prettier/recommended"], "rules": { "prettier/prettier": [ "warn", { "parser": "angular" } ] } } ] }
修复方案
只需修改处理*.ts的override块,添加模板插件并启用规则:
- 在
plugins数组中加入@angular-eslint/template,让ESLint识别模板相关规则 - 在
rules中添加@angular-eslint/template/prefer-self-closing-tags": "error",将规则应用到内联模板
修改后的*.ts override块关键部分:
{ "files": ["*.ts"], "parserOptions": { "project": ["./tsconfig.eslint.json"], "createDefaultProgram": true }, "extends": [ "plugin:@typescript-eslint/recommended", "plugin:@angular-eslint/recommended", "plugin:@angular-eslint/template/process-inline-templates", "plugin:prettier/recommended" ], "plugins": ["rxjs", "@angular-eslint/template"], // 新增模板插件 "rules": { // ... 保留原有所有规则 "@angular-eslint/template/prefer-self-closing-tags": "error" // 新增内联模板规则 } }
原理说明
plugin:@angular-eslint/template/process-inline-templates扩展已经内置了提取ts文件内联模板并使用@angular-eslint/template-parser解析的逻辑,无需手动配置解析器。只需引入@angular-eslint/template插件,ESLint就能将模板规则应用到提取出的内联模板内容上。
另外,请确保tsconfig.eslint.json包含所有需要lint的组件ts文件,避免内联模板所在文件被排除在检查范围外。
内容的提问来源于stack exchange,提问作者hairbo
相关产品推荐
相关产品推荐

