开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
前言
ESlint
被设计为完全可配置的,这意味着你可以关闭每一个规则而只运行基本语法验证,或混合和匹配 ESLint
默认绑定的规则和你的自定义规则,以让 ESLint
更适合你的项目。
本文我们来探讨ESLint
的配置详情。
ESLint
的配置文件,通常在项目根目录下.eslintrc
相关文件中。
module.exports = {
"root": true,
"globals": {
},
"env": {
},
"extends": [
],
"parser": "",
"parserOptions": {
},
"plugins": [
],
"rules": {
}
}
root
默认情况下,ESLint
会在父级中寻找配置文件,直到根目录。
将root
的属性值变为true
后,会停止在父级目录中查找配置文件。
globals
在我们常见的ESLint
的各种规范中,都不允许使用未在代码中声明的变量。但开发中会经常用到一些自带的全局变量。
- 浏览器中的
window
、document
、console
等 - node环境中的
__dirname
等 - Jquery中的全局变量
- Jest中的全局变量
- 代码中自定义的全局变量
- ......
那怎么办呢?其实ESLint
也帮我们考虑到了这种情况,我们需要设置globals
参数去告诉ESLint
,我项目中有哪些全局变量。
module.exports = {
// 配置上 globals 把 $、_ 定义为全局变量
globals: {
"$": "readonly", // 可以读取,不能修改
"_": "writable", // 可以读取,可以修改
}
};
如上所示,我们将$
和_
定义为全局变量,后面参数控制全局变量是否可以修改,readonly
等价于true
,
readonly
/false
—— 只读writable
/true
—— 可写off
—— 禁用该全局变量- 说明:true/false 等价于只读/可写,但不推荐使用。详见ESLint官网
注意:要启用no-global-assign规则来禁止对只读的全局变量进行修改。
那么问题来了,诸如浏览器和node环境中大量的全局变量,我们也要挨个去配置么?
其实不用的,ESLint
帮我们考虑到了这层,我们只需要设置env
字段即可。
env
env
在ESLint
中表示环境,一个环境定义了一组预定义的变量,以便我们在相应环境开发。
可用的环境包括:
browser
- 浏览器环境中的全局变量。node
- Node.js 全局变量和 Node.js 作用域。commonjs
- CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。shared-node-browser
- Node.js 和 Browser 通用全局变量。es6
- 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置ecmaVersion
解析器选项为 6)。worker
- Web Workers 全局变量。amd
- 将require()
和define()
定义为像 amd 一样的全局变量。mocha
- 添加所有的 Mocha 测试全局变量。jasmine
- 添加所有的 Jasmine 版本 1.3 和 2.0 的测试全局变量。jest
- Jest 全局变量。phantomjs
- PhantomJS 全局变量。protractor
- Protractor 全局变量。qunit
- QUnit 全局变量。jquery
- jQuery 全局变量。prototypejs
- Prototype.js 全局变量。shelljs
- ShellJS 全局变量。meteor
- Meteor 全局变量。mongo
- MongoDB 全局变量。applescript
- AppleScript 全局变量。nashorn
- Java 8 Nashorn 全局变量。serviceworker
- Service Worker 全局变量。atomtest
- Atom 测试全局变量。embertest
- Ember 测试全局变量。webextensions
- WebExtensions 全局变量。greasemonkey
- GreaseMonkey 全局变量。
这些环境并不是互斥的,所以你可以同时定义多个。
module.exports = {
"env": {
"browser": true,
"node": true
},
}
以上所示就启用了 浏览器
和 Node.js
的环境。此时再使用相关的全局变量,就不会报错未定义了。
ESLint
中env
的实现也是借助了globals
,有兴趣可参考 env的具体实现
rules
rules
顾名思义,就是ESLint
所校验的规则。
ESLint
本身附带了大量的规则ESLint自带规则
ESlint
规则的设置遵循如下原则:
"off"
或0
- 关闭规则"warn"
或1
- 开启规则,使用警告级别的错误:warn
(不会导致程序退出)"error"
或2
- 开启规则,使用错误级别的错误:error
(当被触发的时候,程序会退出)- 规则只有一个值时,使用
字符串
。需要传递额外参数的时候,使用数组
,数组内后续内容会以参数的形式传入
module.exports = {
"rules": {
"no-console": 'warn', // console 报警
"quotes": ['error', 'single'] // 引号必须单引号
}
}
以上定义了两条规则
- 代码中出现
console
的时候warning - 引号规则中,将第二位
single
作为参数传入,整体代表引号是双引号的时候error
rules
属性可以做下面的任何事情以扩展(或覆盖)规则:
-
启用额外的规则
-
改变继承的规则级别而不改变它的选项:
- 基础配置:
"eqeqeq": ["error", "allow-null"]
- 派生的配置:
"eqeqeq": "warn"
- 最后生成的配置:
"eqeqeq": ["warn", "allow-null"]
- 基础配置:
-
覆盖基础配置中的规则的选项
- 基础配置:
"quotes": ["error", "single", "avoid-escape"]
- 派生的配置:
"quotes": ["error", "single"]
- 最后生成的配置:
"quotes": ["error", "single"]
- 基础配置:
plugins
虽然ESlint
有了大量的内部规则,但我们开发中可能会遇到这些规则覆盖不了的情况,那怎么办呢?
ESLint
支持使用第三方插件。在使用插件之前,你必须使用 npm 安装它。常见的有:
eslint-config-airbnb
eslint-config-react
- ......
在配置文件里配置插件时,可以使用 plugins
关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin-
前缀。
module.exports = {
"plugins": [
"vue"
]
}
上述就是针对vue
所开发的第三方插件,完整的名称是eslint-plugin-vue
,里面针对vue
的特定场景开发了一些规则。
需要注意的是,plugins
仅仅只是加载了插件,并不代表着启用相关的规则。
启用插件需要在rules
中明确,或者使用extends
你可以理解为,
plugin
只是定义了一些函数的实现方法,具体的调用还是需要在rules
或extends
中
extends
虽然我们要按照不同的需求、风格、项目去配置不同的规则,但项目中的很多规则都是大同小异的,如果每个项目都需要将繁琐的各种规则去配置一遍,那就显得有点不近人情了。这时候就需要用到extends
了
extends
顾名思义,继承,就是将别人整理好的规则继承下来,直接用到自己的项目当中。它所继承的东西,就是一份别人已经配置好的.eslintrc.js
文件。
extends
属性值可以是到基本配置文件的绝对路径,也可以是相对路径。ESLint 解析一个相对于使用它的配置文件的基本配置文件的相对路径。
extends
属性值可以省略包名的前缀 eslint-config-
。
大致可分为三类:
ESLint
内置规则包- 第三方规范包
- 第三方插件中的规范包
ESLint
内置规则包
内置规则包指的是跟随ESLint
一同下载好的规则包:
eslint:recommended
仅使用ESLint
推荐的规则eslint:all
使用ESLint
内置的所有规则
具体规则内容可查看ESLint内置规则
ESLint官方提示: 这些配置 不推荐在产品中使用,因为它随着 ESLint 版本进行更改。使用的话,请自己承担风险
module.exports = {
"extends": [
"eslint:recommended",
]
}
第三方规范包
第三方规范包指的是广大人民群众贡献的规范包,常见的有:
eslint-config-airbnb
eslint-config-react
- ......
extends
属性值可以省略包名的前缀 eslint-config-
。
module.exports = {
"extends": [
"airbnb",
]
}
第三方插件中的规范包
这里对应的是plugin
中已引入的包。
此类extends
属性值由以下组成
plugin:
- 包名 (省略了前缀,比如,
vue
) /
- 配置名称 (比如
base
)
以eslint-plugin-vue
为例,我们需要先在plugins
中引入,然后再继承具体的规则。比如:plugin:vue/base
module.exports = {
"plugins": [
"vue",
"@typescript-eslint"
],
"extends": [
"plugin:vue/base",
]
}
parser
解析器,ESLint
会通过解析器将我们写的代码转化成ESTree
(AST的一种),ESLint
会对ESTree
进行校验
Espree
ESLint 默认的 parser ,只转换 js,默认支持 ES5 的语法,可以通过制定 parserOptions 给 Espree 传递如下选项。
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
}
- ecmaVersion 可以开启更高 ES 版本的校验(已加入ES标准的语法,不包括实验性的语法),但需要注意的是一些新标准中的语法对 ESLint 的版本也有要求,如果发现ESLint 不支持校验,可能需要升级 ESLint 版本
- sourceType 可以设置为 "script",如果使用 ESModule 可以设置为 "module"
@babel/eslint-parser
该 parser
允许你使用 ESLint
校验所有 babel code。
ESLint
的默认解析器和核心规则仅支持最新的最终 ECMAScript
标准,不支持 Babel 提供的实验性(例如新功能)和非标准(例如Flow
或TypeScript
类型)语法。
@babel/eslint-parser
是允许 ESLint
在由 Babel
转换的源代码上运行的解析器。
当你使用 babel
时,babel
的解析器会把你的 code 转换为 AST
,该解析器会将其转换为 ESLint
能懂的 ESTree
。
该 praser
的 parserOptions
默认配置如下:
module.exports = {
parser: "@babel/eslint-parser",
parserOptions: {
requireConfigFile: true, // 是否需要 babel 配置文件
sourceType: "module", // script 或者 module
allowImportExportEverywhere: false, // 设置为 true,import 和 export 声明 可以出现在文件的任务位置,否则只能出现在顶部
ecmaFeatures: {
globalReturn: false, // 设置为 true,当 sourceType 为 script 时,允许全局 return
},
babelOptions: {
configFile: "path/to/config.js", // babel 的配置文件,可以不传
},
},
};
官方提醒 虽然
@babel/eslint-parser
可以解析TypeScript
,但我们目前不支持使用@babel/eslint-plugin
中的规则检测TypeScript
。这是因为TypeScript
社区以@typescript-eslint
为中心,我们希望避免重复工作。此外,由于@typescript-eslint
在底层使用TypeScript
,所以它的规则可以是类型感知的,这是Babel没有能力做到的。
@typescript-eslint
ESLint
识别的 AST
也就是它默认的 parser
最终转换出来的 AST
数据内容和格式(ESTree
),与 typescript
的 parser
转换出来的 AST
的内容和格式是不一样的,所以 ESLint
是不能识别 typescript
的 parser
转换出来的 AST
内容。