前端代码规范-ESLint
ESLint 的作用是根据配置参数识别 ECMAScript/JavaScript 代码问题的工具,可以提前明确错误信息,并且可以使代码风格一致,减少错误的发生。本文介绍的是V8版本的
自己总结的小文章
.eslintrc 文件配置项的作用
1. plugins 中所定义得 plugin 作用是什么?
在 .eslintrc 文件中声明插件(如 plugins: ["myplugin"])主要是为了让 ESLint 知道你将使用哪些插件。不会做其他额外的操作。
这一步骤是必要的,因为插件提供了额外的功能,如自定义规则、解析器、处理器等。因为在.eslintrc 中是定义了 plugin 就会根据它的名称进行对应文件的查找,在 extends 和 rules 中直接使用 plugin 的 名称就能简写且 eslint就会按它定的规则来找目录。
2. 什么时候使用 extends
extends 继承插件的配置时,通常是引用插件中的 configs 对象。
示例配置
假设你想要定义一个只包含 rules 的简单配置,你可以像这样定义:
// 插件的 index.js 文件
module.exports = {
configs: {
simpleRules: {
rules: {
'myplugin/no-unused-variable': 'warn',
'myplugin/other-rule': 'error',
},
},
},
};
使用 extends
当你在 .eslintrc 文件中使用 extends 选项来继承这个简单的配置时,你需要指定配置的名称,而不是仅仅写 plugin:myplugin。正确的用法如下:
{
"plugins": ["myplugin"],
"extends": ["plugin:myplugin/simpleRules"]
}
3. 为什么要显示的配置 Plugin 中的规则
在 Plugin 中直接导出 rules 时,并需要用到 plugin 中的规则时,需要显示的定义,因为在定义 Plugins 时,并没有自动导入 rules
{
2 "plugins": ["myplugin"],
3 "rules": {
4 "myplugin/no-unused-variable": "warn", // 显式启用规则
5 "myplugin/other-rule": "error", // 显式启用规则
6 // 更多规则 ...
7 }
8}
4. parser 解析器的更换
ESLint 默认的解析器是 Esprima, 当使用 TS 时,需要设置成 typescript-eslint/parser 用 ts 的解析器来更好的进行代码的检测
5. processors 处理器的使用
在需要解析非标准格式的文件时,可以配置 processors 来处理文件。比如 .vue 格式的文件,在 eslint-plugin-vue 中就有定义处理器,专门处理 .vue 文件。
配置文件的优先级
-
ESLint V8 版本之前
- .eslintrc.js
- .eslintrc.cjs
- .eslintrc.yaml
- .eslintrc.yml
- .eslintrc.json
- package.json 下的 eslintConfig 字段 的顺序查找配置,相同目录下只有一个配置文件会生效。
-
其中,常用的是eslintrc.[js|json]格式,下文采用 eslintrc.js 格式。
-
ESLint V9 版本
eslint.config.jseslint.config.mjseslint.config.cjseslint.config.ts(requires additional setup)eslint.config.mts(requires additional setup)eslint.config.cts(requires additional setup)
-
在 V9 版本中 需要导出一个数组对象配置
配置内容
执行环境配置 env
可以同时开启多个
{
env:{
node: true, // Node.js 全局变量和作用域。
browser: true,// 浏览器全局变量。
es6: true // 支持 ES6 语法(不含 ES module),并开启 ES6 语法解析选项。
}
}
开启环境后,ESLint 能正常解析代码中的全局变量,可能还会开启对应的语法解析选项。
全局变量 globals
env可以配置默认的全局变量, 但是一些模块也会注册一些自己的全局变量,如果不配置 globals 会识别失败,需要在配置中指出代码中用到的外部全局变量。
// 语法 {"var_name": "off"|"readonly"|"writable"}
{
globals:{
$: readonly,
globalState: writable
}
}
"off"的作用在于关闭env带来的全局变量,如在支持大部分 ES2015 语法,但不支持 Promise 的浏览器中,可以设置:
{
"env":{
"es6": true
},
"globals":{
"Promise":"off"
}
}
解析选项 parserOptions
在 ESLint 解析的时候提供一些语言特性的支持,如 ES 语法、JSX(不包含React的JSX语法)。ESLint 默认支持 ES5 语法。
{
"parserOptions":{
/* ecmaVersion: 指定 ECMA 语法版本
* 取值:
* - "latest": 使用最新版本,现在 (2021) 等同于 12
* - 版本号:3, 5(默认), 6, 7, 8, 9, 10, 11, 12
* - 年份命名法:2015(=6), 2016(=7), 2017(8) ...
*/
"ecmaVersion": "latest",
/* sourceType: 脚本类型,普通脚本 或 ES 模块脚本
* 取值:"script"(默认) | "module"(ES 模块脚本)
*/
"sourceType":"module",
/* ecmaFeatures: 支持的特性语法*/
"ecmaFeatures": {
// 支持在全局使用 return
"globalReturn": true,
// 默认使用严格模式(ES 5 或 以上)
"impliedStrict": true,
// 支持 JSX 语法
"jsx": true
}
}
}
其他解析器 parser
ESLint 默认使用 Espree 解析器,可以通过 parser 字段使用其他解析器。 解析器需要满足的条件:
- 必须是一个Node模块, 并且在配置文件的项目目录下可以找到
- 满足ESLint解析器接口
如果项目中用到一些语言增强工具(TypeScript、Babel)或者框架(React、Vue),就需要使用与之对应的解析器。
// Typescript
// 1. 在项目下 install @typescript-eslint/parser
// 2. 配置 parser
{
parser: '@typescript-eslint/parser'
}
注意: 使用其他插件时,parserOptions 仍然有效,它会作为参数传递给解析器.
规则配置 rules
ESLint 提供了大量的 内置规则 并且有自己的 extends eslint:all 和 "eslint:recommended"
规则的配置语法是{"rules": {"rule_name": state | [state, ...options] }}, 其中,state 代表枚举值:
"off" 或者 0:关闭规则,常用于关闭 extends 中的规则"warn" 或者 1:规则校验不通过时发出 warning 提示。"error" 或者 2:规则校验不通过时发出 error 提示,返回 1,表示 lint 检查不通过。
// 例子
{
"rules":{
// 使用 "off", "warn", "error"
"no-console": "warn",
// 使用数字(不推荐,语义不明确)
"for-direction": 1,
// 数组语法,但没有额外配置项
"no-else-return": ["error"],
// 数组语法,一个配置项
"eqeqeq":["error","always"],
// 数组语法,多个配置项
"quotes": ["error", "double", { "avoidEscape": true }]
}
}
使用插件 plugin
下载依赖插件之后,就可以在 ESLint 的 plugins 数组中添加该配置文件需要使用的插件。不过,插件的各项规则配置都是默认关闭的,所以 plugins 只是使用插件功能的前提,你必须在 rules extends env等配置项中开启你需要的规则特性。
{
"plugins":["jest"],
"extends": ["plugin:jest/recommended"],
"env":{
"jest/global":true
},
"rules":{
"jest/valid-expect": "error"
}
}
插件的命名
ESLint 对插件的命名做了规定:
eslint-plugin-<plugin-name>缩写<plugin-name>: 如eslint-plugin-jquery缩写jquery@<scope>/eslint-plugin-<plugin-name>缩写@<scope>/<plugin-name>: 如@jquery/eslint-plugin-jquery缩写@jquery/jquery。@<scope>/eslint-plugin缩写@<scope>: 如@jquery/eslint-plugin缩写@jquery
一般使用不含 eslint-plugin 的简写形式
plugins 属性值可以省略包名中的 eslint-plugin- 前缀。
extends 属性值由以下内容组成:
plugin:包名(可以省略其前缀,如 react 是 eslint-plugin-react 的缩写)/配置名称: 在自定义插件中导出的 configs 定义的 rules 组(如 recommended),在下文中还有提到
// JSON 格式的配置文件的示例:
{
"plugins": [
"react"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"rules": {
"react/no-set-state": "off"
}
}
插件能带来什么
一个插件可以执行许多功能,包括但不限于添加新的规则和导出可共享的配置
ESLint 使用 <plugin-name>/XXX 的方式指定插件内的规则或其他配置。根据
ESLint Docs: Working with Plugins, 一个插件能带来:
- 额外的规则,如
{"rules": {"react/boolean-prop-naming": "warning"}} - 环境,如
{"env": {"jest/global": true}} - 配置,如
{"extends": ["plugin:react/recommended"]} - 预处理器,如
{"process": "a-plugin/a-processor"}
通过 Glob 匹配应用配置 overrides
overrides 支持通过 Glob 模式 匹配特定文件集合,额外应用不同的配置。比如,我们经常需要在项目中根据文件类型应用不同的规则。
overrides 是一个配置对象数组,里面的对象支持大部分的 ESLint 配置,而且多了用于匹配文件的 files 数组和 excludedFiles 数组。当对文件进行 lint 检查时,目标文件相对于配置文件的相对路径会与这两组 glob 模式进行匹配,如果路径满足files中任何一个,且不满足 excludedFiles 中任何一个模式,则会被应用该配置。
/* ./src 目录下除了 a.js 下的 js 文件应用 no-alert 规则 */
{
"overrides": [
{
"files": ["src/*.js"],
"excludedFiles": "a.js",
"rules": {
"no-alert": "warn"
}
}
]
}
忽略文件 ignorePatterns
ignorePatterns 数组包含了一组 glob 模式,当文件路径匹配其中任意一个时被忽略,作用类似 .gitignore
一般都不希望对打包产物进行 lint 检查:
{
"ignorePatterns": ["**/dist/**", "**/output/**"]
}
使用注释进行配置
ESLint 注释区分 // 和 /**/, 可以在注释的同时说明原因,原因放在配置内容之后,用两个或两个以上 - 隔开。
- 大部分的时候
/*
* 单行关闭
*/
alert('foo'); // eslint-disable-line
// eslint-disable-next-line -- I don't want eslint
alert('foo');
/* eslint-disable-next-line */
alert('foo');
alert('foo'); /* eslint-disable-line */
// eslint-disable-next-line no-alert, quotes, semi
alert('foo');
foo(); // eslint-disable-line plugin/rule-name
/*
* 块关闭
*/
/* eslint-disable */
console.log("bar")
alert('foo');
/* eslint-enable */
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */
/*
* 整个文件关闭,在第一行使用 eslint-disable
*/
/* eslint-disable */
alert('foo');
//...
/* eslint-disable no-alert */
alert('foo');
//...
- 可以直接进行规则配置
/* eslint quotes: ["error", "double"], curly: 2
-----
字符串内容含有'', 不想用转移和模版字符串
*/
const foo="'bar'"
- 全局变量
// var1 只读,var2 读写
/* global var1, var2: writable */
- 环境
/* eslint-env node, mocha */
配置层级与规则合并
配置文件层级
尽管一个目录下只有一个配置文件会生效,但 ESLint 支持在不同目录层级下放置多个配置文件。执行文件 lint 时,会从当前文件的目录开始,逐级往上查找配置文件,直到根目录或 遇到 {"root": true} 的配置,并合并不同层级的配置。
注:应该在项目根目录下设置 {"root": true} 避免不必要的查找和影响。
配置的优先级
由于 ESLint 支持多处配置,配置之间可能会冲突,需要规定优先级:
- 配置类型上: 注释 > 命令行参数 > 配置文件
- 文件层级上:(相对目标文件)近 > 远同一目录内:(只会采用一个配置文件)js > cjs > yaml > yml > json > package.json
- 同一配置内:overrides > rule > extends
- 同一选项内:后者 > 前者
规则的覆盖
当多个地方的rules配置出现相同规则时,
-
如果该规则没有配置选项(只支持错误等级),则简单应用最高优先级。
-
如果该规则支持额外配置选项,且高优先级的规则配置没提供选项,则继承低优先级的选项;否则,只应用高优先级的配置和选项。如:
-
"eqeqeq": ["error", "allow-null"]+"eqeqeq": "warn"(高优先级) ="eqeqeq": ["warn", "allow-null"] -
"quotes": ["error", "single", "avoid-escape"]+"quotes": ["error", "single"](高优先级) ="quotes": ["error", "single"]
-
小小结
本文就是介绍一下 eslint 的配置说明,就以 .eslintrc 文件配置项的作用为代表,可以了解到为什么不同的 plugin 部分用来 extends 部分用来重写 rules. 这样大家在就了解了什么样的插件该如何使用的问题,它的执行就是这样执行的。