Angular - ESLint & Prettier config

Record adding eslint and prettier specifications to our angular project.


自从参与了项目的code reveiew工作后,可谓带上了痛苦面具。根据commit msg 可以看出明明是一处非常简单的改动,为何不相干的文件也会出现在changes里?
单引号、双引号混用、缩进有时是 2 空格有时是 4 空格、末尾的分号时有时无... 甚至连调试的console.log都出现在了PR里。甚至为了找到关键的代码修改要把不相干的change过一遍,极大的降低了review效率。
归根结底,大家的配置没有统一。这些看似微不足道的风格差异,在团队协作中却极大地降低了代码的可读性和维护性,甚至影响到后续的代码追踪。
我终于忍不了了,最终,我成功配置了 ESLint + Prettier, 只需要执行npm run lint:fix便可以修复项目中绝大多数的lint issue.


ESLint & Prettier

ESLint: 是目前前端领域最主流的静态代码分析工具。随着TSLint 的淘汰,Angular CLI 从版本 12 开始也已官方弃用 TSLint,转而支持 ESLint。

Prettier: 是一个代码格式化工具,专注于代码风格。相信使用过VS Code的同学都用过这个插件,根据简单的配置,然后强制执行统一的代码格式(如缩进、换行、引号等)。

我们将二者结合起来使用,ESLint 负责质量检查和逻辑检查,Prettier 负责风格格式化。

Angular 项目中配置 Eslint & Prettier

EsLint

给angular项目配置 esLint 可以用完全手动配置的方式,也可以用官方cli 提供的快捷指令将 eslint集成到我们的项目里:

bash 复制代码
ng add @angular-eslint/schematics@14

我的项目angular是14版本的,这里我指定了一下版本号。cli会自动帮我们安装eslint所需的依赖包并生成eslint的配置文件(基础的配置文件,需要根据需求进行拓展)。

angular.json 中已配置 ng lint 目标(使用 @angular-eslint/builder, cli已经帮我们配置好了):

json 复制代码
{
  "lint": {
    "builder": "@angular-eslint/builder:lint",
    "options": {
      "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
    }
  }
}

然后我们可以直接运行

git bash 复制代码
//package.json中已经添加了脚本 "lint": "ng lint",
npm run lint

发现lint已经可以正常使用了。

Prettier

接着我们安装 Prettier, 来丰富lint的功能。

git bash 复制代码
npm install -D prettier eslint-config-prettier eslint-plugin-prettier

prettier: Prettier 核心库。

eslint-config-prettier: 关闭所有与 Prettier 规则冲突的 ESLint 规则。

eslint-plugin-prettier: 将 Prettier 作为 ESLint 规则来运行,这样我们就能用 eslint --fix 来同时完成格式化和代码检查修复。

创建.prettierrc 配置文件

language 复制代码
//.prettierrc
{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "arrowParens": "always",
  "bracketSpacing": true,
  "endOfLine": "lf"
}

.prettierignore 文件

language 复制代码
node_modules
dist
coverage
package-lock.json
pnpm-lock.yaml
yarn.lock
.angular
.vscode

可以根据实际项目进行调整。
接着我们把prettier集成到lint配置文件中

json 复制代码
"extends": [
  "plugin:@angular-eslint/recommended",
  "plugin:@angular-eslint/template/process-inline-templates",
  "plugin:prettier/recommended"
]

"rules": {
  "prettier/prettier": "error"
},
"plugins": ["prettier"]

extends前两项配置是脚手架帮我们配置的angular推荐配置,我们新加了一条 prettier 的配置。会关闭与 Prettier 冲突的 ESLint 规则,由 prettier/prettier 来统一代码风格。

Extending lint rules

目前我们只解决了代码风格的基本问题,还没有达到我们的最终目的。我们还要将覆盖 TS、模块导入导出顺序、类成员顺序、Promise 安全等。
继续安装依赖:

git bash 复制代码
npm i -D eslint-plugin-simple-import-sort eslint-plugin-import eslint-import-resolver-typescript

eslint-plugin-simple-import-sort 提供导入自动排序能力。
eslint-import-resolver-typescript 使 ESLint 能根据 tsconfig.json 解析路径别名。
继续编辑我们的eslint config

json 复制代码
"plugins": ["@typescript-eslint", "import", "simple-import-sort", "prettier"],
"settings": {
  "import/resolver": {
    "typescript": {
      "project": "tsconfig.json"
    }
  }
},
"rules": {
  "@angular-eslint/directive-selector": [
    "error",
    {
      "type": "attribute",
      "prefix": "app",
      "style": "camelCase"
    }
  ],
  "@angular-eslint/component-selector": [
    "error",
    {
      "type": "element",
      "prefix": "app",
      "style": "kebab-case"
    }
  ],
  "simple-import-sort/imports": "error",
  "simple-import-sort/exports": "error",
  "import/no-duplicates": "error",
  "import/newline-after-import": [
    "error",
    {
      "count": 1
    }
  ],
  "@typescript-eslint/explicit-function-return-type": [
    "error",
    {
      "allowExpressions": false,
      "allowHigherOrderFunctions": false,
      "allowTypedFunctionExpressions": false
    }
  ],
  "@typescript-eslint/explicit-member-accessibility": [
    "error",
    {
      "accessibility": "explicit",
      "overrides": {
        "accessors": "explicit",
        "constructors": "no-public"
      }
    }
  ],
  "@typescript-eslint/member-ordering": [
    "error",
    {
      "default": [
        "signature",
        "public-static-field",
        "protected-static-field",
        "private-static-field",
        "public-decorated-field",
        "protected-decorated-field",
        "private-decorated-field",
        "public-instance-field",
        "protected-instance-field",
        "private-instance-field",
        "public-abstract-field",
        "protected-abstract-field",
        "private-abstract-field",
        "public-constructor",
        "protected-constructor",
        "private-constructor",
        "public-static-method",
        "protected-static-method",
        "private-static-method",
        "public-instance-method",
        "protected-instance-method",
        "private-instance-method"
      ]
    }
  ],
  "@typescript-eslint/no-floating-promises": "error",
  "@typescript-eslint/no-misused-promises": "error",
  "@typescript-eslint/consistent-type-imports": [
    "error",
    {
      "prefer": "type-imports",
      "disallowTypeAnnotations": false
    }
  ],
  "@typescript-eslint/no-explicit-any": [
    "error",
    {
      "ignoreRestArgs": false
    }
  ],
  "@typescript-eslint/no-unused-vars": [
    "error",
    {
      "argsIgnorePattern": "^_",
      "varsIgnorePattern": "^_"
    }
  ],
  "no-console": [
    "warn",
    {
      "allow": ["warn", "error"]
    }
  ],
  "prettier/prettier": "error"
}

后续的配置重点总结:

显式返回类型explicit-function-return-type 强制函数声明必须标注返回类型。代码更加规范化。
类成员顺序member-ordering 统一 public/private、静态/实例成员的声明顺序。
导入规范simple-import-sort 自动排序,import/no-duplicates 去重,import/newline-after-import 强制导入与代码间空行,让代码更有条理。
Promise 安全no-floating-promisesno-misused-promises 避免隐式未处理或误用 Promise。
Prettier 集成plugin:prettier/recommended 关闭冲突规则,prettier/prettier 报告格式问题。

配置好了eslint规则后,我们就可以执行

git bash 复制代码
npm run lint

我们就可以在命令行查看根据我们的配置规则生成的report。里面详细的列出了有eslint issue的文件

快速修复:

git bash 复制代码
//package中脚本 "lint:fix": "ng lint --fix"
npm run lint:fix

执行脚本后, 会发现很多简单的esLint issue已经被自动修复了。

VS Code Plugins install and config

我们可以配合vs code 中的 eslint 和 prettier插件使用。安装好插件后, 会发现项目中有lint issue的代码都被划上了红线(如果没有请重启vs code)。

我们还需要对vs code配置文件做一些修改,使得每次保存文件的时候,可以自动的格式化我们的代码。
打开vs code 的setting.json文件

json 复制代码
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.organizeImports": false
  },
  "eslint.validate": ["typescript", "html"],
  "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "[scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }
}

先用 Prettier 统一格式,再由 ESLint 自动修复, 再次更改代码后,保存文件便可以自动格式化代码。

Summary

1.如使用路径别名,eslint-import-resolver-typescript 会按 tsconfig.json 解析。
2.推荐使用angular cli 为项目添加eslint, 本人尝试过DIY 安装, 坑非常多!!!比如由于@angular-eslint 和eslint版本兼容问题,每次执行 npm run lint 都会报错,不能正常使用。
3.Prettier v3 需 eslint-plugin-prettier v5 等等