ESLint+Prettier代码规范实践

1,039 阅读2分钟

ESLint+Prettier代码规范实践

前提

本文并不单独讲解 ESLint 和 Prettier 如何配置和运行。

问题

想在团队中推行一定的代码规范,并给不符合规范的代码做检测和提示。

方案

代码规范校验使用 ESLint,但是一开始 ESLint 只有检测告诉你哪里有问题,常常出现的情况就是一堆 warning,改起来很痛苦。后来 ESLint 提供了 $ ESLint filename --fix 的命令可以自动帮你修复一些不符合规范的代码。Prettier 是一个代码格式化工具,可以帮你把代码格式化成可读性更好的格式,最典型的就是一行代码过长的问题。

Lint和Prettier区别

那 ESLint 和 Prettier 的区别是什么呢?eslint(包括其他一些 lint 工具)的主要功能包含代码格式的校验,代码质量的校验。而 Prettier 只是代码格式的校验(并格式化代码),不会对代码质量进行校验。代码格式问题通常指的是:单行代码长度、tab长度、空格、逗号表达式等问题。而代码质量问题指的是:未使用变量、三等号、全局变量声明等问题。

Lint和Prettier配合使用

为什么要两者配合使用?因为,第一在 ESLint 推出 --fix 参数前,ESLint 并没有自动化格式代码的功能,要对一些格式问题做批量格式化只能用 Prettier 这样的工具。第二 ESLint 的规则并不能完全包含 Prettier 的规则,两者不是简单的谁替代谁的问题。但是在 ESLint 推出 --fix 命令行参数之后,如果你觉得 ESLint 提供的格式化代码够用了,也可以不使用 Prettier。

ESLint 和 Prettier 相互合作的时候有一些问题,对于他们交集的部分规则,ESLint 和 Prettier 格式化后的代码格式不一致。导致的问题是:当你用 Prettier 格式化代码后再用 ESLint 去检测,会出现一些因为格式化导致的 warning。这个时候有两个解决方案:

  1. 运行 Prettier 之后,再使用 eslint --fix 格式化一把,这样把冲突的部分以 ESLint 的格式为标准覆盖掉,剩下的 warning 就都是代码质量问题了。
  2. 在配置 ESLint 的校验规则时候把和 Prettier 冲突的规则 disable 掉,然后再使用 Prettier 的规则作为校验规则。那么使用 Prettier 格式化后,使用 ESLint 校验就不会出现对前者的 warning。

为什么不能先使用 ESLint 再使用 Prettier。针对方案1,如果你后使用 Prettier,那么格式化后提交的代码在下一次或者别人 checkout 代码后是通不过 lint 校验的。针对方案2,其实是可以的,但是本人在实践中看社区方案的时候有提到某些情况下 eslint --fix 和 prettier 混用会出现格式问题。所以保险起见还是先用 perttier 格式化,再用 eslint 命令校验,而不用 eslint --fix 命令去格式化。

使用总结

1、前端项目必然要使代码规范,不论是 js 还是 ts 项目。
2、如前面说说 prettier 是擅长代码格式的校验,eslint擅长代码质量的校验。虽说 eslint 也能格式校验,但是并没有 prettier 那么强势。对于 eslint 和 prettier 使用顺序问题,前面已做解释。
3、vscode 及其插件(prittier)很容易做到编码格式风格统一,逐步强化团队协作中代码统一问题,再结合 git hook 做到 eslint 检验通过,这时团队代码风格和质量就能保持一致。

项目实践

目前有三个流行方案,分别是 Airbnb 、StandardGoogle,严格程度对比是 Airbnb > Google > Standard,所以普遍使用Airbnb的多。

对于eslint,prettier规则冲突的实践方案

方案一

  1. 安装 prettier-eslint(Tip:所有方案前提是你已经安装 eslint 和 prettier 相关包):

    $ npm install --save-dev prettier-eslint prettier-eslint-cli
    
  2. 运行

    $ npm prettier-eslint "src/**/*.js"
    

    prettier-eslint 会一次执行 prettier 和 eslint --fix 命令。整个流程是:Code ➡️ prettier ➡️ eslint --fix ➡️ Formatted Code。prettier-eslint 的各种参数请参看 github.com/prettier/pr… 。

方案二

方案二的思路主要是在 eslint 的规则配置文件上做文章,安装特定的 plugin,把其配置到规则的尾部,实现 prettier 规则对 eslint 规则的覆盖。

  1. 安装 plugin:

    $ npm install --save-dev eslint-config-prettier
    
  2. 在 .eslintrc.* 文件里面的 extends 字段添加:

    {
      "extends": [
        ...,
        "已经配置的规则",
    +   "prettier",
    +   "prettier/@typescript-eslint"
      ]
    }
    

    我使用的是 TypeScript,所以 plugin 的名字是 prettier/@typescript-eslint。

    如果你想 disable 掉更多的规则可以是如下:

    {
      "extends": [
        ...,
        "已经配置的规则",
        "prettier",
        "prettier/@typescript-eslint",
        "prettier/babel",
        "prettier/flowtype",
        "prettier/react",
        "prettier/standard",
        "prettier/unicorn",
        "prettier/vue"
      ]
    }
    

    看名字应该能猜到每个对应的是 disable 哪些规则了吧。

  3. 完成上述两步可以实现的是运行 eslint 命令会按照 prettier 的规则做相关校验,但是还是需要分别运行 prettier 和 eslint 命令。社区有一个方案整合了上述两步,在使用 eslint --fix 时候,实际使用 prettier 来替代 eslint 的格式化功能。
    安装:

    $ npm install --save-dev eslint-plugin-prettier
    

    修改 .eslintrc.*

    {
      "extends": [
        ...,
        "已经配置的规则",
        "plugin:prettier/recommended"
      ]
    }
    

    这个时候你运行 eslint --fix 实际使用的是 Prettier 去格式化文件。eslint-plugin-prettier 具体详细的配置见:github.com/prettier/es…

和VSCode集成使用

上面所有讲到的内容都是在你写完代码去校验的,使用的是命令行工具。如果你是一个新手,对规范不是很熟悉,那么碰到的问题就是写完代码运行命令行工具后产生海量的 warning。这个时候改起来真的很打击积极性。如果能够在写的代码的时候让编辑器提示就能及时改正了。自然我们社区也提供了很多方案,各家的编辑器 Atom、Sublime、VSCode 等主流的编辑器都有相关的插件。我就以 VSCode 为例:

  1. 下载 ESLint Extension

image.png

vscode插件

为了开发方便,我们常常在VSCode中集成一些辅助插件。如prettier、eslint,使得代码在保存或者代码变动的时候自动进行prettier、eslint --fix等。 在settings.json文件中修改eslint配置:

{
  'eslint.enable': true, //是否开启vscode的eslint
  'eslint.autoFixOnSave': true, //是否在保存的时候自动fix eslint
  'eslint.options': {
    //指定vscode的eslint所处理的文件的后缀
    extensions: ['.js', '.ts', '.tsx'],
  },
  'eslint.validate': [
    //确定校验准则
    'javascript',
    'javascriptreact',
    {
      language: 'html',
      autoFix: true,
    },
    {
      language: 'typescript',
      autoFix: true,
    },
    {
      language: 'typescriptreact',
      autoFix: true,
    },
  ],
};
  1. 配置 .eslintrc.*
module.exports =  {
  parser:  '@typescript-eslint/parser',
  extends:  [
    'plugin:@typescript-eslint/recommended',
    'prettier/@typescript-eslint',
    'plugin:prettier/recommended'
  ],
  parserOptions:  {
    ecmaVersion:  2018,
    sourceType:  'module'
  },
  // 其他配置
};
  1. 因为我使用了 TypeScript 所以 .eslintrc.* 配置项的值和 javascript 有点不一样,但是原理是一样的。如果你没有使用 TypeScript 那么到上面步骤就结束了。但是 VSCode 的 ESLint 插件没有天然支持 ts 文件,所以我们还必须自己建立一个设置文件。在项目根目录下新建 .vscode/settings.json 文件,内容如下:

    {
      "eslint.validate": [
        "javascript",
        "javascriptreact",
        { 
          "language": "typescript",
          "autoFix": true
        },
        { 
          "language": "typescriptreact",
          "autoFix": true
        }
      ]
    }
    

你就可以看到编辑器对代码有实时提示了。

强制校验和格式化

讲到这里两个工具配合使用已经讲好了,但是这些步骤都依赖于人工自觉,要做到一点点强制功能,我们就可以用到 husky lint-staged 来在 git commit 前强制代码格式化和代码校验。

  1. 安装

    $npm install --save-dev husky lint-staged
    
  2. 修改 package.json:

    {
      "name": "project-name",
      ...,
      + "husky": {
      +     "hooks": {
      +         "pre-commit": "lint-staged"
      +     }
      + },
      + "lint-staged": {
      +     "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
      +     "prettier --write",
      +     "eslint",
      +     "git add"
      +     ]
      + },
    }
    
  3. 那么在运行 git commit 时候,自动会先去运行 prettier --write 格式化代码,再运行 eslint 校验代码是否符合规范。这两步都通过后才会提交代码。如果任何一步失败,则会停止提交。

如果你使用方案一,lint-staged 配置的命令:

{
  "name": "project-name",
  ...,
  +  "husky": {
  +    "hooks": {
  +      "pre-commit": "lint-staged"
  +    }
  +  },
  + "lint-staged": {
  +   "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
  +     "prettier-eslint",
  +     "git add"
  +   ]
  + },
}

如果你使用了方案二中的 eslint-plugin-prettier,lint-staged 配置的命令:

{
  "name": "project-name",
  ...,
  +  "husky": {
  +    "hooks": {
  +      "pre-commit": "lint-staged"
  +    }
  +  },
  + "lint-staged": {
  +   "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
  +     "eslint --fix",
  +     "git add"
  +   ]
  + },
}