配置 ESLint
阅前悉知
本章节基于 ESLint v8 版本进行编写。由于 v9 版本在配置上与 v8 版本有所不同,因此,如果您使用的是 v9 版本,请参考《文档 - ESLint 中文网》。
在制定团队 SOP 阶段,我们已经了解了编码规范的重要性以及完成了编码规范的制定。接下来,我们需要将编码规范应用到实际开发中,确保团队成员遵循编码规范。如果通过代码审查来手动检查代码规范,那么工作量会非常大,而且容易出错。好在,我们可以借助自动化工具来帮助我们自动检查代码规范,这些自动化工具有 ESLint、Stylelint、Prettier 等。
本文将较为系统的介绍 ESLint,以及 ESLint 如何结合 Prettier 使用。关于 Stylelint 介绍和使用会在另一篇文章中详细说明,请参考《第 13 章:配置 Stylelint》。
ESLint 概述
ESLint 的使用非常简单,只需三步即可:
- 安装 ESLint
- 配置 ESLint 规则
- 执行 ESLint 运行指令
下面是官网中的例子
在项目中安装 ESLint 包:
shellnpm install --save-dev eslint
添加任一支持的配置文件格式的
.eslintrc
文件。shell# 创建 JavaScript 配置文件 touch .eslintrc.js
在
.eslintrc
文件中添加配置。阅读配置 ESLint 文档学习如何添加规则、环境、自定义配置、插件以及其他内容。js// .eslintrc.js 示例 module.exports = { env: { browser: true, es2021: true }, extends: 'eslint:recommended', parserOptions: { ecmaVersion: 'latest', sourceType: 'module' } }
使用 ESLint 命令行检查代码:
shellnpx eslint project-dir/ file1.js
可以看到,在项目中引入 ESLint 是非常简单。
但……!这样就完成 ESLint 在项目中的配置工作了吗?显然不是。
上面的操作只是将 ESLint 引入到项目中,并没有真正用起来。前面说到 ESLint 是用于检测 JavaScript 代码的工具,其目的是使代码风格保持统一。
所以我们还需要将团队的编码规范写进 ESLint 中,让其帮助我们检测开发人员编写的代码是否符合团队编码规范。
此外,有些文件(如dist/
、public/
等目录中的文件)并不是开发人员编写的,或者并不想对其进行检测。所以我们也需要让 ESLint 忽略一些文件的检测。
还有,npx eslint project-dir/ file1.js
运行指令太长,难以编写,而且手动编写运行代码极容易出错。因此也需要将 ESLint 运行指令封装成更加简洁的指令。
还有,ESLint 只能检测 JavaScript 代码,HTML、CSS 怎么吧?所以也要实现 HTML、CSS 代码的检测。
最后,ESLint 只检测不太行,最好自动帮忙修正错误;只有执行指令才进行检查修正不够及时,要在保存代码的时候就执行。
接下来,我们将一个个的实现上面这些诉求。
第一步,编写配置文件
ESLint 重难点就是配置文件的编写。可以说,编写好配置文件就算完成 ESLint 配置工作的 80%。
首先,我们简单了解一下配置文件的的构成。
TIP
ESLint 配置文件支持多做文件格式,本文采用的是.eslintrc.js
。详见:配置文件 - ESLint - 插件化的 JavaScript 代码检查工具
配置文件构成
常见的 ESLint 配置文件属性如下:
属性 | 说明 | 案例 |
---|---|---|
root | 指定当前配置文件所在目录为根目录。ESLint 在执行时会自动向上(父目录)查找配置文件,直到文件系统的根目录(/ )、当前用户的主目录(~/ )或指定 root: true 时停止。一般情况下,我们都会在项目文件根目录中放置 ESLint 配置文件,并将root 设置为true 。 | {"root":true} |
env | 指定 JavaScript 代码的所用到的全局变量。其接受一个对象,可配置多种运行环境。JavaScript 生态中有多个运行时、版本、扩展和框架。每个所支持的全局变量都不尽相同。例如,项目代码中用到了 ES6 的写法,我们就需要通过env 属性来向 ESLint 声明 ES6 的全局变量。所支持的环境可查看:语言选项 - ESLint - 插件化的 JavaScript 代码检查工具 | {"env":{"browser": true,"node": true}} |
ignorePatterns | 指定 Eslint 在检测时忽略的文件或者目录。其值是个正则数组。等同于.eslintignore 文件。 | {ignorePatterns:["temp.js","**/vendor/*.js"]} |
parserOptions | 指定 ESLint 支持的 JavaScript 语言解析器。其接受一个对象,可配置多种语言解析器。ESLint 默认支持 ES5 语法的解析,如果我们想要支持 ES6、JSX 或者 TS 等,需要在parserOptions 中声明对应的解析器。否则 ESLint 将无法解析相关代码。注意配合env 属性,env 声明的是语法中的全局变量,parserOptions 声明的是支持的语法。 | {"parserOptions":{"ecmaVersion":6}} |
globals | 自定义全局变量。其接受一个对象。全局变量为属性名,可操作性为属性值。对于每个全局变量的键,将相应的值设置为 "writable" 以允许变量被覆盖,或者 "readonly" 以禁止覆盖。 | {"globals":{"var1":"writable","var2":"readonly"}} |
plugins | 指定要使用的 ESLint 插件。属性值可以是一个插件名称,也可以是插件名称组成的数组。详见:配置插件与解析器 - ESLint - 插件化的 JavaScript 代码检查工具 | {"plugins": ["react"]} |
extends | 指定扩展配置文件。配置文件使用扩展后,就可以继承另一个配置文件的所有特征(包括规则、插件和语言选项)并修改所有选项。属性值可以是一个字符串,也可以是字符串数组。字符串的值可来源于四种途径:配置文件的路径、可共享配置的名称、eslint:recommended 、eslint:all | { "extends": "eslint:recommended"} |
rules | 自定义规则。在rules 属性中可以自定义 ESLint 规则来覆盖默认规则、扩展规则以及插件规则。其值为对象。详见:配置规则 - ESLint - 插件化的 JavaScript 代码检查工具 | {"rules": {"quotes": ["error", "double"]}} |
插件与扩展说明
扩展(extends)
extends
属性配置的扩展指的是 ESLint 的配置文件。ESLint 会读取extends
属性指定的 ESLint 配置文件,并将其合并到当前的配置文件中。例如下面的 ESLint 配置:
module.exports = {
extends: ['eslint:recommended', 'plugin:vue/recommended']
}
当 ESLint 读取这个配置文件的时候,会去读取eslint:recommended
关联的配置文件以及plugin:vue/recommended
关联的配置文件,然后将这两个配置文件的配置合并到当前配置文件中。
插件(plugins)
插件(plugins
)是一个可以为 ESLint 添加各种扩展功能的 npm 包。它的作用同样也是用来扩展 ESLint。但与extends
属性不同的是,插件(plugins
)不仅仅有配置文件,还可以包括:插件定义规则、插件定义配置、插件定义环境、插件定义处理器。
TIP
在使用插件(plugins)时,单单在pluguns
中声明还不行,需要在相应的配置属性中显式声明。
如下示例:
{
// ...
// 引入插件jquery、@foo/foo、@bar
"plugins": [
"jquery", // eslint-plugin-jquery
"@foo/foo", // @foo/eslint-plugin-foo
"@bar" // @bar/eslint-plugin
],
// 启用插件@foo/foo中推荐的配置,@bar中推荐配置
"extends": ["plugin:@foo/foo/recommended", "plugin:@bar/recommended"],
// 启用插件jquery的a-rule规则,@foo/foo的some-rule规则,@bar的another-rule规则
"rules": {
"jquery/a-rule": "error",
"@foo/foo/some-rule": "error",
"@bar/another-rule": "error"
},
// 启用插件jquery的环境配置,@foo/foo的环境配置,@bar的环境配置
"env": {
"jquery/jquery": true,
"@foo/foo/env-foo": true,
"@bar/env-bar": true
}
// ...
}
不太准确的说,plugins
只是引入插件,启用插件的功能还需要在对应的配置属性的声明开启。
定制自己的 ESLint 配置
了解 Eslint 配置原理后,我们就可以根据编码规范定制自己的 ESLint 配置。
IMPORTANT
一般情况下,在确认 ESLint 配置清单时,优先采用在业内较为成熟通用的 ESLint 配置,然后在其基础上根据团队编码规范进行调整。
例如,这样一个 ESLint 配置:
配置清单
- 基于 ESLint 内置的推荐规则
eslint:recommended
- 使用
eslint-plugin-vue
插件 - 使用 node 环境变量
- 只读的全局变量
$
- 一些自定义规则
配置文件如下:
module.exports = {
root: true,
env: {
node: true
},
// 全局变量。详见https://zh-hans.eslint.org/docs/latest/use/configure/language-options#-6
globals: {
$: 'readonly'
},
// eslint 规则扩展
extends: [
'eslint:recommended', // 启用ESLint内置的推荐规则
'plugin:vue/essential' // 启用eslint-plugin-vue插件中的essential规则
],
// 配置插件,由插件名称组成的列表。可以省略插件名称中的 eslint-plugin- 前缀。
plugins: [
'vue' // 等价于eslint-plugin-vue,用于检测.vue文件种的`<template>`和<script>`以及.js文件种的Vue代码
],
// 自定义规则,详见:https://zh-hans.eslint.org/docs/latest/use/configure/rules
rules: {
'vue/name-property-casing': ['error', 'PascalCase'],
'no-console': 'off',
'no-debugger': 'off',
'no-spaced-func': 'error',
'no-const-assign': 'error',
'no-alert': 'off',
'no-useless-escape': 'off',
'no-control-regex': 'off',
'space-before-function-paren': ['off', 'always']
}
}
第二步,设置文件忽略规则
像node_moudle
、dist
等目录下的文件并不需要进行代码校验。因此我们需要设置 ESLint 文件忽略规则,让 ESLint 不要去校验这些文件。
ESLint 有两种方式设置 ESLint 文件忽略规则:
在配置文件中添加
ignorePatterns
。适用于忽略文件数量较少的情况。创建忽略匹配模式的专用文件(默认为
.eslintignore
)。适用于忽略文件数量较多的情况。
下面以.eslintignore
文件为例:
node_modules
dist
# 忽略手动引入的第三方组件
src/assets/ueditor
# 忽略静态文件
public
INFO
第三步,封装运行指令
完成所有配置后,就可以在终端执行 ESLint 命令来运行 ESLint 了。
ESLint 命令基本构成如下:
eslint [options] [file|dir|glob]*
即:eslint
关键字+options
可选项(可多选)+file|dir|glob
检测的目标(可多选)
关于 options
ESLint 支持的options
非常多,功能齐全。我们甚至可以通过options
来实现配置文件的所有配置。不过我们并不需要编写很繁琐的运行指令,这是因为配置文件已经完成绝大多数的配置工作。
大多数情况下,我们只需要在运行指令中声明所要使用的配置文件、文件忽略规则文件以及检测文件的匹配规则即可。
以下是一些常用的options
:
--ext [String] 指定支持的文件后缀,如:【.js,.ts,.vue,.html】
-c, --config path::String 指定配置文件,默认.eslintrc.*
--ignore-path path::String 指定忽略文件。默认.eslintignore
--cache 开启缓存功能,值检测变动的文件
--fix 开启自动修复功能
INFO
更多 options 说明可查看:ESLint - 命令行界面
编写运行指令
接下来基于前面的配置编写 ESLint 运行指令。
INFO
要求如下:
- 使用项目根目录下配置文件
.eslintrc.js
- 使用项目根目录下的文件忽略规则文件
.eslintignore
- 对后缀为【
.js
,.ts
,.vue
,.html
】的文件进行检测 - 启用缓存功能
- 检测项目根目录下符合条件的全部文件
对应的指令如下:
eslint --config .eslintrc.js --ext .js,.vue,.html,.ts --ignore-path .eslintignore --cache ./
上面这条指令有点长,如果每次运行都需要手写这条指令就会很繁琐且容易出错。因此,还需要把这条指令封装进package.json
的scripts
中。
{
"scripts": {
"lint": "eslint --config .eslintrc.js --ext .js,.vue,.html,.ts --ignore-path .eslintignore --cache ./"
},
}
这样,只需要在终端执行npm run lint
或yarn lint
即可。
开启修复功能
如果想要 ESLint 在检测代码的时候自动修正不合规的代码。只需要在运行指令中添加 option
--fix
。
上面的指令则变为:
eslint --config .eslintrc.js --ext .js,.vue,.html,.ts --ignore-path .eslintignore --cache --fix ./
在 package.json 中可以基于srcipt:lint
脚本指令这样编写:
{
"scripts": {
"lint": "eslint --config .eslintrc.js --ext .js,.vue,.html,.ts --ignore-path .eslintignore --cache ./",
"lint:fix": "yarn lint --fix"
},
}
如果你的项目没有使用 yarn,则:npm run lint --fix
配合 Prettier 来使用
Prettier 是一个比 ESLint 更加擅长代码格式(如:单行代码长度,tab,引号等)校验的工具。不过相较于 ESLint,Prettier 少了代码质量(未使用变量,三等号,箭头函数的使用)校验的功能。
当然,我们可以将两者结合使用,让 Prettier 来完成代码格式校验,ESLint 来完成代码质量校验。
由于,两者的规则存在一定的冲突。所以两者结合使用首先要解决的是规则冲突问题。
可以安装eslint-config-prettier
扩展来解决这个问题。
eslint-config-prettier 说明
eslint-config-prettier
扩展禁用了所有与格式相关的 ESLint 规则。
- 安装
eslint-config-prettier
扩展
yarn add --dev eslint-config-prettier
.eslintrc.js
文件中添加如下配置:
{
"extends": [
"prettier" // eslint-config-prettier 可简写成 prettier
]
}
冲突解决了还不行。ESLint 无法识别 Prettier 的差异报告,所以我们还需安装eslint-plugin-prettier
插件,将 Prettier 作为 ESLint 规则运行,并将差异当做 ESLint 问题报告给 ESLint。
- 安装
eslint-plugin-prettier
:
yarn add --dev eslint-plugin-prettier
- 添加配置:
{
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
上面两者的配置合起来就是:
{
"extends": ["prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
此外,我们可以简写成:
{
"extends": ["plugin:prettier/recommended"]
}
制定 Prettier 规则
完成上面的配置后,我们就可以放心使用 Prettier 了。
Prettier 和 ESLint 一样有配置文件:
- 配置文件:
.prettierrc.js
- 文件忽略规则文件:
.prettierignore
在使用时我们并不需要手动去执行 Prettier 指令,ESLint 会自动读取 Prettier 的配置文件来运行 Prettier。
.prettierrc.js
举例:
module.exports = {
printWidth: 120, // 一行的字符数,如果超过会进行换行,默认为80。注意,该值必须设置为120,否则与eslint规则冲突
tabWidth: 2, // 一个tab代表几个空格数,默认为2
useTabs: false, // 是否使用tab进行缩进,默认为false,表示用空格进行缩减
singleQuote: true, // 字符串是否使用单引号,默认为false,使用双引号
semi: true, // 行尾是否使用分号,默认为true
arrowParens: 'avoid', // 箭头函数只有一个参数时,是否忽略括号,默认为'always'
trailingComma: 'none', // 在对象和数组字面量中使用一致的拖尾逗号,默认'es5'
endOfLine: 'lf' // default: auto
}
开启【保存代码时自动执行 ESLint】功能
如果觉得每次只能在终端执行指令才能使用 ESLint 代码检测修正还不够方便。那我们可以开启【保存代码时自动执行 ESLint】功能。
TIP
【保存代码时自动执行 ESLint】功能需要配合代码编辑器的来实现。目前主流的代码编辑器(如:VSCode)都支持该功能。
VSCode 配置
首先,安装 VSCode 的 ESLint 扩展插件。
然后在.vscode/settings.json
配置文件中添加如下配置:
{
"editor.formatOnSave": true, // 开启编辑器保存自动格式化代码功能
"eslint.format.enable": true, // 开启eslint扩展插件代码格式化功能
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.VSCode-eslint" // 指定默认编辑器代码格式化工具为dbaeumer.VSCode-eslint
},
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.VSCode-eslint"
},
"[vue]": {
"editor.defaultFormatter": "dbaeumer.VSCode-eslint"
}
}
配置说明
editor.formatOnSave
和eslint.format.enable
是最主要的两个配置项,一个是开启 VSCode 的保存代码时自动格式化代码功能;一个是开启 ESLint 扩展插件的代码检测和格式化功能。两者配合使用即可实现在保存代码时自动根据 ESLint 配置进行代码修正。
可能你会遇到代码保存时自动修正后的代码,会导致 ESLint 报错。这是因为 VSCode 设置的【默认代码格式化工具】并不是 ESLint(可能是 prettier),从而导致了修正结果和 ESLint 规范不一致。
因此我们要将【默认代码格式化工具】改为 ESLint。即:
{
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.VSCode-eslint" // 指定默认编辑器代码格式化工具为dbaeumer.VSCode-eslint
},
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.VSCode-eslint"
},
"[vue]": {
"editor.defaultFormatter": "dbaeumer.VSCode-eslint"
}
}
自动格式化工作流程说明
VSCode 自动格式化工作流程说明
第一步,当 VSCode 通过 ESLint 进行代码修正时,会自动去项目中寻找配置文件(如:.eslintrc.js
)和.eslintignore
文件。如果没有找到文件,则会采用 ESLint 默认配置。
第二步,根据配置文件中的配置来进行代码修正。
因此,必须保证 ESLint 配置文件在项目目录中,最好是在根目录下。否则【保存时自动格式】的代码也会和通过指令执行 ESLint 的结果不一致。
写在最后
本章节简单阐述了 ESLint 的作用以及如何配置使用 ESLint。ESLint 不但可以规范代码风格,提高代码质量,而且还可以通过 ESLint 的插件机制,实现代码的自动修正,从而提高开发效率。借助 ESLint,可以把编码规范中的大多数细节交给工具去识别,从而使得代码审查人员可以把精力集中到业务逻辑、代码质量等自动化工具无法兼顾的编码规范上。