Skip to main content

ESLint 配置及其原理

JavaScript 是一个动态的弱类型语言,在开发中比较容易出错。因为没有编译程序,为了寻找 JavaScript 代码错误通常需要在执行过程中不断调试。像 ESLint 这样的可以让程序员在编码的过程中发现问题而不是在执行的过程中。

ESLint 是一个开源的 JavaScript 代码检查工具,使用 Node.js 编写,由 Nicholas C. Zakas 于 2013 年 6 月创建。

ESLint 内置了一些规则,可以在使用过程中自定义规则,所有的规则默认都是禁用的。

一、ESLint 的生态依赖包

1、基础包

ESLint:检查代码的主要工具,所以的一切都是基于此包。

2、解析器(parser)

  • babel-eslint:该依赖包允许使用实验特性时,依然能够用上 ESLint 语法检查。

  • typescript-eslint: Typescript 语法的解析器,类似于 babel-eslint 解析器。

3、扩展的配置

  • eslint-config-airbnb:该包提供了所有 Airbnb 的 ESLint 配置,作为一种扩展的共享配置,可以修改覆盖掉某些不需要的配置,该工具包包含了 react 的相关 ESLint 规则(eslint-plugin-reacteslint-plugin-jsx-a11y),所以安装此依赖包的时候还需要安装这两个插件。

  • eslint-config-airbnb-base:与上一个包的区别是,这个依赖包不包含 react 的规则,一般用于服务端检查。

  • eslint-plugin-jsx-a11y:jest 和 enzyme 专用的校验规则,保证一些断言语法可以让 ESLint 识别而不会发出警告。

  • eslint-config-prettier: 将会禁用掉所有那些非必须或和 prettier 冲突的规则。

4、插件

  • eslint-plugin-babel: 和 babel-eslint 一起用的一款插件,babel-eslint 在将 eslint 应用于 Babel 方面做得很好,但它不能更改内置规则来支持实验性特性。而 eslint-plugin-babel 重新实现了有问题的规则,因此就不会误报一些错误信息。

  • eslint-plugin-import: 该插件支持 ES6 import/export 语法的校验, 并防止一些文件路径拼错或者是导入名称错误的情况。

  • eslint-plugin-jsx-a11y: 该依赖包专注于检查 JSX 元素的可访问性。

  • eslint-import-resolver-webpack: 可借助 webpack 的配置来辅助 eslint 解析。

  • eslint-import-resolver-typescript:和 eslint-import-resolver-webpack 类似,主要是为了解决 alias 的问题。

  • eslint-plugin-react: React 专用的校验规则插件。

  • eslint-plugin-jest: Jest 专用的 ESLint 规则校验插件。

  • eslint-plugin-prettier: 该插件辅助 ESLint 可以平滑地与 Prettier 一起协作,并将 Prettier 的解析作为 ESLint 的一部分,在最后的输出可以给出修改意见。这样当 Prettier 格式化代码时,依然能遵循 ESLint 的规则。如果禁用所有和代码格式化相关的 ESLint 规则,该插件可以更好的工作。所以可以使用 eslint-config-prettier 禁用掉所有的格式化相关的规则。

  • typescript-eslint:Typescript 辅助 ESLint 的插件。

  • eslint-plugin-promise:promise 规范写法检查插件,附带了一些校验规则。

5、辅助优化流程

  • husky: git 命令 hook 专用配置。

  • lint-staged: 可以定制在特定的 git 阶段执行特定的命令。

6、Prettier

Prettier 相关的包有好多个,除了上面列举的两个,可能还会用到下面的三个:

其中最基础的是 prettier,然后需要用 eslint-config-prettier 去禁用掉所有和 prettier 冲突的规则,这样才可以使用 eslint-plugin-prettier 去以符合 eslint 规则的方式格式化代码并提示对应的修改建议。

为了让 prettier 和 eslint 结合起来,诞生了 prettier-eslint 这个工具,但它只支持输入代码字符串,不支持读取文件,因此又有了 prettier-eslint-cli

二、ESLint 的配置方式

ESLint 一般用 .eslintrc.* 的配置文件进行配置,如果放在项目的根目录中,则会作用于整个项目。如果在项目的子目录中也包含着 .eslintrc.* 文件,则子目录中文件的检查以该文件为准。

ESLint 采用逐级向上查找的方式查找 .eslintrc.* 文件,当找到带有 "root": true 配置项的 .eslintrc.* 文件时,将会停止向上查找。

ESLint 可以通过以下几种方式进行配置:

用 .eslintrc.js 配置

module.exports = {
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"rules": {
}
};

用 .eslintrc.yaml 配置

env:
browser: true
es6: true
node: true
extends: "eslint:recommended"
globals:
Atomics: readonly
SharedArrayBuffer: readonly
parserOptions:
ecmaVersion: 2018
sourceType: module
rules: {}

用 .eslintrc.json 配置

{
"name": "three",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"eslint": "^6.6.0"
}
}

用 package.json 配置

可以在 package.json 中创建一个 eslintConfig 属性来进行 ESLint 配置:

{
"name": "four",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"eslint": "^6.6.0"
},
"eslintConfig": {
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"rules": {}
}
}

三、.eslintrc 的配置参数

点击查看 ESLint 配置文档

//.eslintrc.js
module.exports = {
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"no-unused-vars": "off"
}
};

1、env

env 用于指定脚本的运行环境,可用的参数是:es6broswernode等。

每种环境都有一组特定的预定义全局变量。例如 node 环境下有 global 全局变量,browser 环境下有 window 全局变量,jquery 环境下有 $ 全局变量,ES6 环境下有 Set 等新特性全局变量。

2、extends

extends 用于指定扩展的配置,配置支持递归扩展,支持规则的覆盖和聚合。

3、globals

globals 用于定义全局变量。

4、parserOptions

parserOptions 用于指定想要支持的 JavaScript 语言选项。当默认的解析器从 Espree 改为 babel-eslint 时就需要指定 parseOptions。默认情况下,ESLint 支持 ES5 语法,可以覆盖该设置以启用对 ES 其它版本和 JSX 的支持。

注意:支持 JSX 语法并不等同于支持 React。React 对 ESLint 无法识别的 JSX 语法应用特定的语义。如果正在使用 React 并且想要 React 语义支持,可以使用 eslint-plugin-react

5、plugins

plugins 用于配置指定检查规则的插件。

6、rules

rules 用于自定义规则,可以覆盖掉 extends 的配置。

7、忽略检查

可以通过在项目目录下建立 .eslintignore 文件,并在其中配置忽略掉对哪些文件的检查。也可以在 package.json 文件的 eslintIgnore 字段进行配置。

需要注意的是,不管有没有在 .eslintignore 中进行配置,eslint 都会默认忽略掉对 /node_modules/** 的检查。

四、ESLint 的 rules

常见 rules 属性值:

  • "off" 或 0:关闭规则
  • "warn" 或 1:开启规则,使用警告,程序不会退出
  • "error" 或 2:开启规则,使用错误,程序退出
"no-alert": 0,              // 禁止使用 alert、confirm、prompt
"no-array-constructor": 2, // 禁止使用数组构造器
"no-bitwise": 0, // 禁止使用按位运算符
"no-caller": 1, // 禁止使用 arguments.caller 或 arguments.callee
"no-catch-shadow": 2, // 禁止 catch 子句参数与外部作用域变量同名
"no-class-assign": 2, // 禁止给类赋值
"no-cond-assign": 2, // 禁止在条件表达式中使用赋值语句
"no-console": 2, // 禁止使用 console
"no-const-assign": 2, // 禁止修改 const 声明的变量
"no-constant-condition": 2, // 禁止在条件中使用常量表达式 if(true) if(1)
"no-continue": 0, // 禁止使用 continue
"no-control-regex": 2, // 禁止在正则表达式中使用控制字符
"no-debugger": 2, // 禁止使用debugger
"no-delete-var": 2, // 不能对 var 声明的变量使用 delete 操作符
"no-div-regex": 1, // 不能使用看起来像除法的正则表达式 /=foo/
"no-dupe-keys": 2, // 在创建对象字面量时不允许键重复 {a:1,a:1}
"no-dupe-args": 2, // 函数参数不能重复
"no-duplicate-case": 2, // switch 中的 case 标签不能重复
"no-else-return": 2, // 如果if语句里面有return,后面不能跟else语句
"no-empty": 2, // 块语句中的内容不能为空
"no-empty-character-class": 2, // 正则表达式中的 [] 内容不能为空
"no-empty-label": 2, // 禁止使用空 label
"no-eq-null": 2, // 禁止对 null 使用 == 或 != 运算符
"no-eval": 1, // 禁止使用 eval
"no-ex-assign": 2, // 禁止给 catch 语句中的异常参数赋值
"no-extend-native": 2, // 禁止扩展 native 对象
"no-extra-bind": 2, // 禁止不必要的函数绑定
"no-extra-boolean-cast": 2, // 禁止不必要的 bool 转换
"no-extra-parens": 2, // 禁止非必要的括号
"no-extra-semi": 2, // 禁止多余的冒号
"no-fallthrough": 1, // 禁止 switch 穿透
"no-floating-decimal": 2, // 禁止省略浮点数中的 0 .5 3.
"no-func-assign": 2, // 禁止重复的函数声明
"no-implicit-coercion": 1, // 禁止隐式转换
"no-implied-eval": 2, // 禁止使用隐式 eval
"no-inline-comments": 0, // 禁止行内备注
"no-inner-declarations": [2, "functions"],// 禁止在块语句中使用声明(变量或函数)
"no-invalid-regexp": 2, // 禁止无效的正则表达式
"no-invalid-this": 2, // 禁止无效的 this,只能用在构造器,类,对象字面量
"no-irregular-whitespace": 2, // 不能有不规则的空格
"no-iterator": 2, // 禁止使用 __iterator__ 属性
"no-label-var": 2, // label 名不能与 var 声明的变量名相同
"no-labels": 2, // 禁止标签声明
"no-lone-blocks": 2, // 禁止不必要的嵌套块
"no-lonely-if": 2, // 禁止 else 语句内只有if语句
"no-loop-func": 1, // 禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)
"no-mixed-requires": [0, false],// 声明时不能混用声明类型
"no-mixed-spaces-and-tabs": [2, false], // 禁止混用 tab 和空格
"linebreak-style": [0, "windows"], // 换行风格
"no-multi-spaces": 0, // 不能用多余的空格
"no-multi-str": 2, // 字符串不能用 \ 换行
"no-multiple-empty-lines": [1, {"max": 3}], // 空行最多不能超过2行
"no-native-reassign": 2, // 不能重写 native 对象
"no-negated-in-lhs": 2, // in 操作符的左边不能有 !
"no-nested-ternary": 0, // 禁止使用嵌套的三目运算
"no-new": 1, // 禁止在使用 new 构造一个实例后不赋值
"no-new-func": 1, // 禁止使用 new Function
"no-new-object": 2, // 禁止使用 new Object()
"no-new-require": 2, // 禁止使用 new require
"no-new-wrappers": 2, // 禁止使用 new 创建包装实例,new String、new Boolean、new Number
"no-obj-calls": 2, // 不能调用内置的全局对象,比如 Math()、JSON()
"no-octal": 2, // 禁止使用八进制数字
"no-octal-escape": 2, // 禁止使用八进制转义序列
"no-param-reassign": 2, // 禁止给参数重新赋值
"no-path-concat": 0, // node 中不能使用 __dirname 或 __filename 做路径拼接
"no-plusplus": 0, // 禁止使用 ++,--
"no-process-env": 0, // 禁止使用 process.env
"no-process-exit": 0, // 禁止使用 process.exit()
"no-proto": 2, // 禁止使用 __proto__ 属性
"no-redeclare": 2, // 禁止重复声明变量
"no-regex-spaces": 2, // 禁止在正则表达式字面量中使用多个空格 /foo bar/
"no-restricted-modules": 0, // 如果禁用了指定模块,使用就会报错
"no-return-assign": 1, // return 语句中不能有赋值表达式
"no-script-url": 0, // 禁止使用 javascript:void(0)
"no-self-compare": 2, // 不能比较自身
"no-sequences": 0, // 禁止使用逗号运算符
"no-shadow": 2, // 外部作用域中的变量不能与它所包含的作用域中的变量或参数同名
"no-shadow-restricted-names": 2,// 严格模式中规定的限制标识符不能作为声明时的变量名使用
"no-spaced-func": 2, // 函数调用时 函数名与 () 之间不能有空格
"no-sparse-arrays": 2, // 禁止稀疏数组,[1,,2]
"no-sync": 0, // nodejs 禁止同步方法
"no-ternary": 0, // 禁止使用三目运算符
"no-trailing-spaces": 1, // 一行结束后面不要有空格
"no-this-before-super": 0, // 在调用 super() 之前不能使用 this 或 super
"no-throw-literal": 2, // 禁止抛出字面量错误 throw "error";
"no-undef": 2, // 不能有未定义的变量
"no-undef-init": 2, // 变量初始化时不能直接给它赋值为 undefined
"no-undefined": 2, // 不能使用 undefined
"no-unexpected-multiline": 2, // 避免多行表达式
"no-underscore-dangle": 1, // 标识符不能以_开头或结尾

// 禁止不必要的嵌套 var isYes = answer === 1 ? true : false;
"no-unneeded-ternary": 2,
"no-unreachable": 2, // 不能有无法执行的代码
"no-unused-expressions": 2, // 禁止无用的表达式

// 不能有声明后未被使用的变量或参数
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
"no-use-before-define": 2, // 未定义前不能使用
"no-useless-call": 2, // 禁止不必要的 call 和 apply
"no-void": 2, // 禁用 void 操作符
"no-var": 0, // 禁用 var,用 let 和 const 代替

// 不能有警告备注
"no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
"no-with": 2, // 禁用 with
"array-bracket-spacing": [2, "never"], // 是否允许非空数组里面有多余的空格
"arrow-parens": 0, // 箭头函数用小括号括起来
"arrow-spacing": 0, // => 的前/后括号
"accessor-pairs": 0, // 在对象中使用 getter/setter
"block-scoped-var": 0, // 块语句中使用 var
"brace-style": [1, "1tbs"], // 大括号风格
"callback-return": 1, // 避免多次调用回调什么的
"camelcase": 2, // 强制驼峰法命名
"comma-dangle": [2, "never"], // 对象字面量项尾不能有逗号
"comma-spacing": 0, // 逗号前后的空格
"comma-style": [2, "last"], // 逗号风格,换行时在行首还是行尾
"complexity": [0, 11], // 循环复杂度
"computed-property-spacing": [0, "never"],// 是否允许计算后的键名什么的
"consistent-return": 0, // return 后面是否允许省略
"consistent-this": [2, "that"], // this 别名
"constructor-super": 0, // 非派生类不能调用 super,派生类必须调用 super
"curly": [2, "all"], // 必须使用 if(){} 中的 {}
"default-case": 2, // switch语句最后必须有default
"dot-location": 0, // 对象访问符的位置,换行的时候在行首还是行尾
"dot-notation": [0, { "allowKeywords": true }], // 避免不必要的方括号
"eol-last": 0, // 文件以单一的换行符结束
"eqeqeq": 0, // 必须使用全等
"func-names": 0, // 函数表达式必须有名字
"func-style": [0, "declaration"], // 函数风格,规定只能使用函数声明/函数表达式
"generator-star-spacing": 0, // 生成器函数 * 的前后空格
"guard-for-in": 0, // for in循环要用if语句过滤
"handle-callback-err": 0, // nodejs 处理错误
"id-length": 0, // 变量名长度
"indent": [2, 2], // 缩进风格
"init-declarations": 0, // 声明时必须赋初值

// 对象字面量中冒号的前后空格
"key-spacing": [0, { "beforeColon": false, "afterColon": true }],
"lines-around-comment": 0, // 行前/行后备注
"max-depth": [0, 4], // 嵌套块深度
"max-len": [0, 80, 4], // 字符串最大长度
"max-nested-callbacks": [0, 2], // 回调嵌套深度
"max-params": [0, 3], // 函数最多只能有 3 个参数
"max-statements": [0, 10], // 函数内最多有几个声明
"new-cap": 2, // 函数名首行大写必须使用 new 方式调用,首行小写必须用不带 new 方式调用
"new-parens": 2, // new 时必须加小括号
"newline-after-var": 2, // 变量声明后是否需要空一行
"object-curly-spacing": [0, "never"],// 大括号内是否允许不必要的空格
"object-shorthand": 0, // 强制对象字面量缩写语法
"one-var": 1, // 连续声明
"operator-assignment": [0, "always"], // 赋值运算符 += -= 什么的
"operator-linebreak": [2, "after"], // 换行时运算符在行尾还是行首
"padded-blocks": 0, // 块语句内行首行尾是否要空行
"prefer-const": 0, // 首选 const
"prefer-spread": 0, // 首选展开运算
"prefer-reflect": 0, // 首选 Reflect 的方法
"quotes": [1, "single"],// 引号类型 `` "" ''
"quote-props":[2, "always"], // 对象字面量中的属性名是否强制双引号
"radix": 2, // parseInt 必须指定第二个参数
"id-match": 0, // 命名检测
"require-yield": 0, // 生成器函数必须有 yield
"semi": [2, "always"], // 语句强制分号结尾
"semi-spacing": [0, {"before": false, "after": true}],// 分号前后空格
"sort-vars": 0, // 变量声明时排序
"space-after-keywords": [0, "always"],// 关键字后面是否要空一格
"space-before-blocks": [0, "always"], // 不以新行开始的块 { 前面要不要有空格
"space-before-function-paren": [0, "always"], // 函数定义时括号前面要不要有空格
"space-in-parens": [0, "never"], // 小括号里面要不要有空格
"space-infix-ops": 0, // 中缀操作符周围要不要有空格
"space-return-throw-case": 2, // return throw case 后面要不要加空格

// 一元运算符的前/后要不要加空格
"space-unary-ops": [0, { "words": true, "nonwords": false }],
"spaced-comment": 0, // 注释风格要不要有空格什么的
"strict": 2, // 使用严格模式
"use-isnan": 2, // 禁止比较时使用 NaN,只能用 isNaN()
"valid-jsdoc": 0, // jsdoc 规则
"valid-typeof": 2, // 必须使用合法的 typeof 的值
"vars-on-top": 2, // var 必须放在作用域顶部
"wrap-iife": [2, "inside"], // 立即执行函数表达式的小括号风格
"wrap-regex": 0, // 正则表达式字面量用小括号包起来
"yoda": [2, "never"] // 禁止尤达条件

1、rules 的工作原理

eslint rules 的源码中可以看出,每一个 rules 都是一个 node 模块,用 module.exports 导出一个 meta 对象及一个 create 函数。

module.exports = {
meta: {
type: "suggestion",

docs: {
description: "disallow unnecessary semicolons",
recommended: true,
url: "https://eslint.org/docs/rules/no-extra-semi",
},

fixable: "code",
schema: [],

messages: {
unexpected: "Unnecessary semicolon.",
},
},
create(context) {
return {
// callback functions
};
},
};

meta 对象代表了这条规则的元数据,如这条规则的类别、文档、可接收的参数 schema 等等。

create 函数返回一个对象,其中定义了一些在 AST 遍历访问到对应节点需要执行的方法等等。函数接受一个 context 对象作为参数,里面包含了例如可以报告错误或者警告的 context.report()、可以获取源代码的 context.getSourceCode() 等方法,可以简化规则的编写。

function checkLastSegment(node) {
// report problem for function if last code path segment is reachable
}

module.exports = {
meta: { ... },
create: function (context) {
// declare the state of the rule
return {
ReturnStatement: function (node) {
// 在 AST 从上向下遍历到 ReturnStatement node 时执行
},
// 在 AST 从下向上遍历到 function expression node 时执行:
"FunctionExpression:exit": checkLastSegment,
"ArrowFunctionExpression:exit": checkLastSegment,
onCodePathStart: function (codePath, node) {
// 在分析代码路径开始时执行
},
onCodePathEnd: function (codePath, node) {
// 在分析代码路径结束时执行
},
};
},
};

遍历 AST 的过程中会以“从上至下”再“从下至上”的顺序经过节点两次,selector 默认会在下行的过程中执行对应的访问函数,如果需要再上行的过程中执行,则需要添加 :exit

点击查看详细原理代码路径分析

2、如何写一个 rules

每个 rules 需要有三个以该规则名命名的文件,分别是:

  • lib/rules 目录: 一个源文件(例如 no-extra-semi.js
  • tests/lib/rules 目录: 一个测试文件 (例如 no-extra-semi.js)
  • docs/rules 目录: 一个 markdown 文档文件 (例如 no-extra-semi)

下面编写一个简单的 rules,例如禁止块级注释,当代码中使用了块级注释,eslint 将报错:

rules 文件:

lib/rules/no-block-comments.js
module.exports = {
meta: {
docs: {
description: "禁止块级注释",
category: "Stylistic Issues",
recommended: true,
},
},

create(context) {
// 获取源代码
const sourceCode = context.getSourceCode();

return {
Program() {
// 获取源代码中所有的注释
const comments = sourceCode.getAllComments();

const blockComments = comments.filter(({ type }) => type === "Block");

blockComments.length &&
context.report({
node: node,
message: "No block comments",
});
},
};
},
};

rules 的测试文件:

tests/lib/rules/no-block-comments.js
const RuleTester = require("eslint").RuleTester;
const rule = require("../../../lib/rules/no-block-comments");

const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } }); // You do have to tell eslint what js you're using

ruleTester.run("no-block-comments", rule, {
valid: ["var a = 1; console.log(a)"],
invalid: [
{
code: "var a = 1; /* block comments */ console.log(a)",
errors: [
{
messageId: "blockComments",
line: 1,
nodeType: "Block",
},
],
},
],
});

3、如何使用自定义的 rules

将上面写好的 rules 发布到 npm 上,然后在项目中下载使用。

.eslintrc.js
module.exports = {
...
"plugins": [
"eslint-plugin-no-block-comments"
// 发布的 npm 包名称,可以省略 eslint-plugin
],
"rules": { // 启用的规则及其各自的错误级别
'no-console': 'off',
// 引用 no-block-comments 插件中的 no-block-comments 规则
"no-block-comments/no-block-comments": 2
}
};

然后对代码进行检查,在命令行中执行 eslint src 即可看到检查结果。

五、ESLint 的检查原理

要实现静态分析则需要自建一个预编译阶段对代码进行解析。

大部分编译器工作时的三个阶段:

  • 解析:将未经处理的代码解析成更为抽象的表达式,通常为抽象语法树,即 AST。
  • 转换:通过修改解析后的代码表达式,将其转换为符合预期的新格式。
  • 代码生成:将转换后的表达式生成为新的目标代码。

对 eslint 来说,规则校验发生在将 JavaScript 代码解析为 AST 之后,遍历 AST 的过程中。eslint 采用 Espree 来生成AST,具体实现请点击

可以使用 AST explorer 来查看代码被解析后生成的 AST。

六、VSCode 配置 ESlint

1、保存自动格式化

  • 配置方式一
"eslint.autoFixOnSave": false, // 已废弃,被第二种方式替代
  • 配置方式二

官方推荐方式

"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll.eslint": true
}
  • 配置方式三
"eslint.format.enable": true,
"editor.formatOnSave": true

2、状态栏中显示 ESlint

打开状态栏的 ESlint 显示以查看 ESlint 服务是否正常运行:

"eslint.alwaysShowStatus": true

3、不显示 ESlint 校验的警告信息

"eslint.quiet": true

4、项目中配置 VSCode ESlint

  1. 在项目根目录下建立包含 settings.json.vscode 文件夹
  2. settings.json 中设置 ESlint 规则(会覆盖编辑器默认的 ESlint)