ESLint
ESLint是一个用来识别ECMAScript并且按照规则给出报告的代码检测工具,使用它可以避免低级错误,统一代码的风格,从而有效控制代码的质量。
一 生成关于ESLint的配置文件
官方一共提供了三种配置文件:
- JavaScript (eslintrc.js)
- YAML (eslintrc.yaml)
- JSON (eslintrc.json)
根据ESLint的源码,可以看到配置文件的优先级由高到低依次为:
const configFilenames = [
".eslintrc.js",
".eslintrc.yaml",
".eslintrc.yml",
".eslintrc.json",
".eslintrc",
"package.json"
];
我们就以VUE项目中生成.eslintrc.js为例,讲一下该文件的生成和配置。
//全局安装 ESLint
npm install -g eslint
//在项目中创建.esilnt配置文件
./node_modules/.bin/eslint --init
//或者运行
eslint --init
接下来做一些简单的配置:
通过上述的简单配置后,就会在文件夹的根目录生成了一个.eslintrc.js文件。
module.exports = {
//如brower、node环境变量、es6环境变量、mocha环境变量等
"env": {
"browser": true,
"es6": true,
"node": true
},
//继承一套基础配置,如:"@tencent/eslint-config-idata",'standard'
"extends": [
"eslint:recommended",
"plugin:vue/essential"
],
//额外的全局变量
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
//指定传给 parser 的信息,eslint使用的默认是Espree
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
//插件可以用于rules、env和extends等配置中
"plugins": [
"vue"
],
//开启规则和发生错误时报告的等级
"rules": {
// 强制使用单引号
'quotes': ['error', 'single'],
// 在块级作用域外访问块内定义的变量是否报错提示
'block-scoped-var': 0,
}
};
如果项目中出现了多个.eslintrc.js文件,如下图,这两个配置文件会进行合并:
但是如果我们在src/.eslitrc.js中配置了root为true,那么ESLint就会认为src目录为跟目录,不会再向上查找配置。
{
"root":true
}
二 配置参数
1.解析器配置
ESLint的自带的解析器为Espree,除了这个之外还可以指定其他解析器:
- @babel/eslint-parser:使 Babel 和 ESLint 兼容,对一些 Babel 语法提供支持;
- @typescript-eslint/parser:TSLint 被弃用后,TypeScript 提供了此解析器用于将其与 ESTree 兼容,使 ESLint 对 TypeScript 进行支持;
为项目指定某个选择器的原则是什么?
如果你的项目用到了比较新的 ES 语法,比如 ES2021 的 Promise.any(),那就可以指定 @babel/eslint-parser 为解析器;
如果项目是基于 TS 开发的,那就使用 @typescript-eslint/parser;
除了要指定解析器parser之外,还可以额外配置解析器参数parserOption:
{
// ESLint 默认解析器,也可以指定成别的
parser: "espree",
parserOption: {
// 指定要使用的 ECMAScript 版本,默认值 5
ecmaVersion: 5,
// 设置为 script (默认) 或 module(如果你的代码是 ECMAScript 模块)
sourceType: "script",
// 这是个对象,表示你想使用的额外的语言特性,所有选项默认都是 false
ecmafeatures: {
// 是否允许在全局作用域下使用 return 语句
globalReturn: false,
// 是否启用全局 strict 模式(严格模式)
impliedStrict: false,
// 是否启用JSX
jsx: false,
// 是否启用对实验性的objectRest/spreadProperties的支持
experimentalObjectRestSpread: false
}
}
}
2.指定环境env和全局变量
ESLint会检测未声明的变量并发出警告,但是有些变量是我们引入的库声明的,这就需要提前在配置中声明:
{
"globals": {
// 声明 jQuery 对象为全局变量
"$": false // true表示该变量为 writeable,而 false 表示 readonly
}
}
但是在globas中一个个的声明太过繁琐,这时候就需要使用到env,这是对一个环境定义的一组全局变量的预设,类似于babel的preset
{
"env": {
"amd": true,
"commonjs": true,
"jquery": true
}
}
各种不同的环境,ESLint设置了很多预设值。在ESLint包的environment.js文件中可以看到具体的引用,这些引用都来自于globals.json文件,具体的可以去下面地址查看
https://github.com/sindresorhus/globals/blob/main/globals.json
3.配置规则rules
ESLint提供了大量内置的规则,具体有哪些规则可以查看官方文档:
https://eslint.org/docs/rules/
每一条rule接受一个参数,参数的值有以下几个:
- off 或 0:关闭对该规则的校验;
- warn 或 1:启用规则,不满足时抛出警告,且不会退出编译进程;
- error 或 2:启用规则,不满足时抛出错误,且会退出编译进程;
ESLint的规则不仅只有开启和关闭这么简单,每一条规则还有自己的配置项。如果要对某个规则进行配置,就需要使用数组形式的参数。
举个例子,我们看一下quote的规则,根据官网介绍,它支持字符串和对象两个配置项:
根据官网的解释,我们可以这样对quote进行配置:
{
"rules": {
// 使用数组形式,对规则进行配置
// 第一个参数为是否启用规则
// 后面的参数才是规则的配置项
"quotes": [
"error",
"single",
{
"avoidEscape": true
}
]
}
}
配置了这个规则之后,就会对我们的代码产生约束:
// bad
var str = "test 'ESLint' rule"
// good
var str = 'test "ESLint" rule'
4.扩展extends
实际项目中我们不可能一条条的去配置顾着,通常会去使用业内大家广泛认可的规范,然后通过extends去引入这些规范。extends配置的时候接受字符串或者数组,主要有以下几种:
{
extends: [
'eslint:recommended',
'plugin:vue/essential',
'eslint-config-standard', // 可以缩写成 'standard'
'@vue/prettier',
'./node_modules/coding-standard/.eslintrc-es6'
]
}
- eslint 开头的:是 ESLint 官方的扩展;
- plugin 开头的:是插件类型扩展,比如 plugin:vue/essential;
- eslint-config 开头的:来自 npm 包,使用时可以省略前缀 eslint-config-,比如上面的可以直接写成 standard;
- @开头的:扩展和 eslint-config 一样,只是在 npm 包上面加了一层作用域 scope;
- 一个执行配置文件的相对路径或绝对路径;
有哪些常用的,比较知名的扩展呢?
- eslint:recommended:ESLint 内置的推荐规则,即 ESLint Rules 列表中打了钩的那些规则;
- eslint:all:ESLint 内置的所有规则;
- eslint-config-standard:standard 的 JS 规范;
- eslint-config-prettier:关闭和 ESLint 中以及其他扩展中有冲突的规则;
- eslint-config-airbnb-base:airbab 的 JS 规范;
- eslint-config-alloy:腾讯 AlloyTeam 前端团队出品,可以很好的针对你项目的技术栈进行配置选择,比如可以选 React、Vue(现已支持 Vue 3.0)、TypeScript 等;
规则的优先级
- 如果extends配置的是一个数组,那么最终所有规则会进行合并,出现冲突的时候,后面的会覆盖前面的;
- 通过rules单独配置的规则优先级比extends高
5.插件plugins
ESLint虽然可以定义很多rules,以及可以通过extends来引入更多的规则,但是说到底只是检查JS语法。如果要检查VUE中的template或者React中的jsx,就束手无策了。所以引入插件的目的就是为了增强ESLint的检查能力和范围。
ESLint的插件和扩展一样有固定的命名格式,以eslint-plugin-开头,使用的时候可以省略这个头。
npm install --save-dev eslint-plugin-vue eslint-plugin-react
方法一:插件中引入:
{
"plugins": [
"react", // eslint-plugin-react
"vue", // eslint-plugin-vue
]
}
方法二:在扩展中引入,前面有提到过plugin:开头的扩展是进行插件的扩展:
{
"extends": [
"plugin:react/recommended",
]
}
这种通过扩展引入的方式,加载插件的规则如下:
extPlugin = `plugin:${pluginName}/${configName}`
根据上面的引入,插件名(pluginName) 为react,也就是之前安装eslint-plugin-react包,配置名(configName)为recommended。
这里的配置名可以通过eslint-plugin-react的源码去查找:
module.exports = {
// 自定义的 rule
rules: allRules,
// 可用的扩展
configs: {
// plugin:react/recommended
recomended: {
plugins: [ 'react' ]
rules: {...}
},
// plugin:react/all
all: {
plugins: [ 'react' ]
rules: {...}
}
}
}
6.其他各种配置
(1)配置当前目录为root
ESLint检测配置文件步骤:
- 在要检测的文件同一目录里寻找 .eslintrc.* 和 package.json;
- 紧接着在父级目录里寻找,一直到文件系统的根目录;
- 如果在前两步发现有 root:true 的配置,停止在父级目录中寻找 .eslintrc;
- 如果以上步骤都没有找到,则回退到用户主目录 ~/.eslintrc 中自定义的默认配置;
通常我们都习惯把ESLint配置文件放到项目根目录,因此可以为了避免ESLint校验的时候往父级目录查找配置文件,所以需要在配置文件中加上root: true。
(2)添加共享数据
ESLint 支持在配置文件添加共享设置,你可以添加settings对象到配置文件,它将提供给每一个将被执行的规则。如果你想添加的自定义规则而且使它们可以访问到相同的信息,这将会很有用,并且很容易配置:
settings: {
sharedData: 'Hello'
},
这里涉及到一个自定义规则,有兴趣的可以看下一章。
(3)针对个别文件设置新的检查规则
比如webpack的中包含了某些运行时的JS文件,而这些文件是只跑在浏览器端的,所以需要针对这部分文件进行差异化配置:
overrides: [
{
files: ["lib/**/*.runtime.js", "hot/*.js"],
env: {
es6: false,
browser: true
},
globals: {
Promise: false
},
parserOptions: {
ecmaVersion: 5
}
}
]
(4)校验单个文件
// 校验 a.js 和 b.js
npx eslint a.js b.js
// 校验 src 和 scripts 目录
npx eslint src scripts
(5)自动修复部分校验错误的代码
rules 列表项中标识了一个扳手 🔧 图案的规则就标识该规则是可以通过 ESLint 工具自动修复代码的。如何自动修复呢?通过 --fix 即可。比如对于 ESLint Rules 里的这个 semi 规则,它就是带扳手图案的。
当在配置文件配置了 ‘semi’: [2, ‘always’] 后,运行命令:
npx eslint --fix a.js
(6)把校验命令加到package.json
检验命令比较长,也难记,习惯上会把这些命名直接写到 package.json 里:
{
"scripts": {
"lint": "npx eslint --ext .js,.jsx,.vue src",
"lint:fix": "npx eslint --fix --ext .js,.jsx,.vue src",
}
}
(7)过滤一些不需要校验的文件
对于一些公共的 JS、测试脚本或者是特定目录下的文件习惯上是不需要校验的,因此可以在项目根目录通过创建一个 .eslintignore 文件来配置,告诉 ESLint 校验的时候忽略它们:
public/
src/main.js
除了 .eslintignore中指定的文件或目录,ESLint 总是忽略 /node_modules/ 和 /bower_components/ 中的文件;因此对于一些目前解决不了的规则报错,但是如果又急于打包上线,在不影响运行的情况下,我们就可以利用 .eslintignore 文件将其暂时忽略。
三 总结
ESLint的发展时间并不长,只是随着ES6发布,JS语法发生了很大的改动,导致JSLint和JSHint如果不更新解析器就没法检测ES6的代码。而ESLint采用AST的方式对代码进行静态分析,并保留了强大的可扩展性和灵活的配置能力,这也提醒我们在日常的
编码过程中,一定要考虑到后续的扩展能力。
实际的eslint在VUE项目中的应用中还不止这些,通常我们会将ESLint和Prettier结合起来使用,不仅能统一编码规范,也能统一代码风格,具体的用法见下一章。