前提
本文并不单独讲解 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。这个时候有两个解决方案:
- 运行 Prettier 之后,再使用 eslint --fix 格式化一把,这样把冲突的部分以 ESLint 的格式为标准覆盖掉,剩下的 warning 就都是代码质量问题了。
- 在配置 ESLint 的校验规则时候把和 Prettier 冲突的规则 disable 掉,然后再使用 Prettier 的规则作为校验规则。那么使用 Prettier 格式化后,使用 ESLint 校验就不会出现对前者的 warning。
为什么不能先使用 ESLint 再使用 Prettier。针对方案1,如果你后使用 Prettier,那么格式化后提交的代码在下一次或者别人 checkout 代码后是通不过 lint 校验的。针对方案2,其实是可以的,但是本人在实践中看社区方案的时候有提到某些情况下 eslint --fix 和 prettier 混用会出现格式问题。所以保险起见还是先用 perttier 格式化,再用 eslint 命令校验,而不用 eslint --fix 命令去格式化。
方案一实践
-
安装 prettier-eslint(Tip:所有方案前提是你已经安装 eslint 和 prettier 相关包):
$ npm install --save-dev prettier-eslint prettier-eslint-cli
-
运行
$ npm prettier-eslint "src/**/*.js"
prettier-eslint 会一次执行 prettier 和 eslint --fix 命令。整个流程是:Code ➡️ prettier ➡️ eslint --fix ➡️ Formatted Code。prettier-eslint 的各种参数请参看 https://github.com/prettier/prettier-eslint-cli 。
方案二实践
方案二的思路主要是在 eslint 的规则配置文件上做文章,安装特定的 plugin,把其配置到规则的尾部,实现 prettier 规则对 eslint 规则的覆盖。
-
安装 plugin:
$ npm install --save-dev eslint-config-prettier
-
在 .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 哪些规则了吧。
-
完成上述两步可以实现的是运行 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 具体详细的配置见:https://github.com/prettier/eslint-plugin-prettier
和VSCode集成使用
上面所有讲到的内容都是在你写完代码去校验的,使用的是命令行工具。如果你是一个新手,对规范不是很熟悉,那么碰到的问题就是写完代码运行命令行工具后产生海量的 warning。这个时候改起来真的很打击积极性。如果能够在写的代码的时候让编辑器提示就能及时改正了。自然我们社区也提供了很多方案,各家的编辑器 Atom、Sublime、VSCode 等主流的编辑器都有相关的插件。我就以 VSCode 为例:
-
下载 ESLint Extension
配置 .eslintrc.*
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended'
],
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module'
},
// 其他配置
};
- 因为我使用了 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 前强制代码格式化和代码校验。
-
安装
$npm install --save-dev husky lint-staged
-
修改 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" + ] + }, }
那么在运行 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"
+ ]
+ },
}
参考文献
- https://eslint.org/
- https://prettier.io/
- https://restishistory.net/blog/whats-the-difference-between-eslint-and-prettier.html
如果使用的是 TypeScript:
- ESLint如何运用到TS项目
- 如何和Prettier配合使用