You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 18项目中如何让inline template应用自闭合标签ESLint规则

Angular 18.1 让prefer-self-closing-tags规则生效到内联模板的解决方案

问题背景

在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块,添加模板插件并启用规则:

  1. 在plugins数组中加入@angular-eslint/template,让ESLint识别模板相关规则
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 22:32:04