为什么会有ESlint?
要解决问题,就要有规矩,把规矩写到文件里,就是ESlint。 当工作中只有你一个人的时候,什么问题都不是问题,但是当你是团队中的一员时,就会有各种问题。
ESlint是什么?
由尼古拉斯·泽卡斯,在2013年创建,是一个开源的 JavaScript编写的运行在node环境的代码校验和修复工具,使用 Espree 将 JavaScript 代码解析成抽象语法树 (AST),然后通过 AST 来分析我们代码,从而给予我们代码问题提示。
- javascript编写
- 运行在node环境
- 代码质量问题
- 代码风格问题
ESlint怎么用?
终于有一天,你在打dota的时候遇到了一位前端队友,你抱怨了自己遇到的问题,对方友好的给你推荐了ESlint,从此你发现了新大陆。然后小哥哥拉上Lucy和Tony一起开了个会,在你苦口婆心的劝说下,大家终于同意使用2个空格作为缩进,并把它作为第一个ESlint的规则,你们迈进了规范化的学堂。
安装ESlint
由于校验能力是ESlint提供,ESlint是一个javascript编写的node包,所以我们直接安装这个包:
# 安装
yarn global eslint
# 或者
npm install eslint -g
# 使用
eslint dir #校验
eslint dir --fix #修复
编写ESlint配置
情人眼里出西施,一千个人眼里有一千个哈姆雷特。每个团队都可能有更适合自己的校验规则,ESlint当然不会强人所难,其提供了丰富的配置功能,这意味着你可以关闭每一个规则而只运行基本语法验证,或混合和匹配 ESLint 默认绑定的规则和你的自定义规则。主要提供了两种配置方式:
- Configuration Files:文件配置
- Configuration Comments:注释配置(禁用文件、禁用行等)
文件配置
可以配置一个独立的 .eslintrc.*
文件,或者直接在 package.json
文件里的 eslintConfig
字段指定配置,ESLint 会查找和自动读取它们,再者,你可以在命令行运行时指定一个任意的配置文件。
文件种类
- .eslintrc.js
- .eslintrc.yaml
- .eslintrc.yml
- .eslintrc.json
- .eslintrc
- package.json
- 命令行指定
eslint -c、--config filepath
这么多配置方式,我们先随便挑一个 .eslintrc.js
,ok,编写我们的第一个规则,可是我需要配什么东西啊???
配置参数
rules
启用的规则及其错误级别root
配置文件的检索方式env
指定脚本的运行环境。每种环境都有一组特定的预定义全局变量globals
脚本在执行期间访问的额外的全局变量extends
指定一个包含所有配置的扩展文件plugins
第三方插件,其可以提供自己的规则和扩展配置overrides
通过glob对文件进行更精细的配置控制parserOptions
解析器配置,针对es语法解析的配置ecmaVersion
es版本sourceType
es模块
processor
处理器,可以在预处理中转换 JavaScript 代码,然后让 ESLint 检测 JavaScript 代码。parser
解析器,将代码解析为AST语法树。ESLint 默认使用Espree作为其解析器
rules
配置eslint的校验规则,默认,我们能使用的规则,都是eslint内置的规则。规则列表
参数类型
Number
:0
关闭;1
警告;2
报错String
:'off'
、'warn'
、'error'
分别 对应 0、1、2Array
: [<Number|String>, <其它选项>]
// .eslintrc.js
module.exports = {
rules: {
"indent": [1, 2],
"eqeqeq": 2,
"no-unused-vars": "error"
}
}
规则分类
-
Possible Errors
这些规则与 JavaScript 代码中可能的错误或逻辑错误有关。例如: no-dupe-keys
-
Best Practices
这些规则是关于最佳实践的,帮助你避免一些问题。例如:eqeqeq -
Strict Mode
该规则与使用严格模式和严格模式指令有关。例如:no-unused-vars -
Node.js and CommonJS
这些规则是关于Node.js 或 在浏览器中使用CommonJS 的。 -
ECMAScript 6
这些规则只与 ES6 有关, 即通常所说的 ES2015。这里为什么只提了ES6,可能是ES6比较经典:joy:(迈向现代化的重大升级) 例如:no-var
总结为两大类:
- 容易引起程序bug的。
- 视觉上看着很难受的。
root
当我们执行校验命令的时候,ESLint 会在要检测的文件目录里寻找配置文件,紧接着是父级目录,一直到文件系统的根目录,如果都没有,会去找你的家目录配置文件(~/.eslintrc)
ESlint检索配置文件规则:
- 当前目录寻找
- 父级目录寻找,一直到文件系统的根目录
- 如果①和②里都没有,则在家目录寻找
但是如果遇到了某一个配置文件中配置了
root: true
, 则不再向上寻找。 其中①和②,不是或的关系,是并的关系。就是说当前目录和祖先目录都有配置的时候,都会生效。
globals
当访问当前源文件内未定义的变量时,no-undef 规则将发出警告。
- 全局变量未定义的告警是基于 no-undef 规则的。
- 配置方式有3种。
off
禁用、readonly
可用只读、writeable
可用可写 - 由于历史原因,布尔值
false
和字符串值"readable"
等价于"readonly"
。类似地,布尔值true
和字符串值"writeable"
等价于"writable"
。但是,不建议使用旧值。
module.exports = {
"globals": {
"Promise": 'off',
"$": 'readonly',
"App": "writeable"
}
}
env
一个环境定义了一组预定义的全局变量。重点:browser
、node
、es6
。
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 全局变量。- 来自
plugin
的导出
extends
一个配置文件可以被基础配置中的已启用的规则继承。配置
属性值可以是:
String
: 字符串 (配置文件的路径、可共享配置的名称、eslint:recommended
或eslint:all
)Array
:字符串数组,每个配置继承它前面的配置
-
文件路径
module.exports = { extends: "./extends.js" }
-
eslint:*
module.exports = { extends: "eslint:recommended" }
-
可共享配置 可共享的配置 是一个 npm 包,它输出一个配置对象。
extends
属性值可以省略包名的前缀eslint-config-
。module.exports = { extends: ["airbnb", "plugin:vue/essential", "@vue/prettier"] } // 对应三个包:eslint-config-airbnb、eslint-plugin-vue、@vue/eslint-config-prettier
plugins
插件 是一个 npm 包,通常输出规则。一些插件也可以输出一个或多个命名的 配置。plugins
属性值 可以省略包名的前缀 eslint-plugin-
。
使用plugins
输出的extends
, 属性值可以由以下组成:
plugin:${包名}/${包.config.配置名}
以 eslint-plugin-vue 为例
module.exports = {
parserOptions: {
"sourceType": 'module'
},
parser: require.resolve('vue-eslint-parser'),
plugins: ['vue'],
processor: 'vue/.vue',
rules: {
"vue/no-template-key": 2
},
extends: 'plugin:vue/recommended'
}
overrides
若要禁用/覆盖一组文件的配置文件中的规则,请使用 overrides
和 files
。例如:
module.exports = {
rules: {
"semi": 2
},
overrides: [
{
files: ['other-*.js'],
rules: {
"semi": 0
}
}
]
}
parserOptions
ESLint 允许你指定你想要支持的 JavaScript 语言选项。默认情况下,ESLint 支持 ECMAScript 5 语法。你可以覆盖该设置,以启用对 ECMAScript 其它版本和 JSX 的支持。
module.exports = {
parserOptions: {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
}
}
开发一个plugin
- 遵循 eslint-plugin-xxx 或者 @scope/eslint-plugin-xxxx 命名规范
- 使用
yeoman
工具搭配generator-eslint
模板来初始化项目。文档:yeoman、 generator-eslint - 创建并导出规则、共享配置等
到此eslint自身的能力基本就讲完了,但是!我们开发过程中并没有这么麻烦,每次写完代码还要执行一次 eslint命令,这肯定是不行的。所以针对eslint就有了各种应用实践。
应用实践
指各应用框架、IDE对eslint能力的应用
vscode-eslint
安装vscode的eslint扩展后,编码阶段,IDE就可以以波浪线的形式给我们实时提示报错的地方。
vscode的配置
vscode-eslint支持很多配置,一般我们不需要做修改,默认即可。文档
{
"eslint.enable": Boolean, // 为工作区文件夹启用/禁用 ESLint。默认启用
"eslint.probe": Array, // ESLint 验证文件的语言类型。如果对探测语言的验证失败,则扩展程序会说静默。默认为["javascript", "javascriptreact", "typescript", "typescriptreact", "html", "vue", "markdown"]
"eslint.validate": Array, // 和probe类似,废弃了。默认为["javascript", "javascriptreact"]
"eslint.useESLintClass": Boolean, // 是否使用 ESLint 类 API。和 eslint.options配套使用
// 用于配置如何使用ESLint 类 API或CLIEngine API启动 ESLint 的选项。https://eslint.org/docs/developer-guide/nodejs-api#cliengine
"eslint.options": {
"cwd": String, // 默认为process.cwd()。工作目录。这必须是绝对路径。
"extensions": Array, // 要校验的文件扩展
"overrideConfig": Object, // 正常的eslint的配置
"overrideConfigFile": String, // 指定一个配置文件。options.overrideConfig会merge此选项
"useEslintrc": Boolean, // 默认为true。如果是false,则ESLint不会加载配置文件(.eslintrc.*文件),只有构造函数选项的配置是有效的
"fix": Boolean, // 自动修复
}
}
vue-cli
通过集成 @vue/cli-plugin-eslint
实现在开发过程中,输入编译警告、页面上出现错误提示等。@vue/cli-plugin-eslint 源码
git hooks
通过在git钩子中执行 eslint
校验来阻断git的提交
课后习题
- 创建一个plugins
- 创建一个配置
- 创建一个规则
- 还能创建什么?