1. ESLint 简介
关于 ESLint,官方网站 用一句话概括了它的作用:
- Find and fix problems in your JavaScript code. (查找并修复存在于你的 JavaScript 代码中的问题)
ESLint 中文网 是这么介绍它的:
- ESLint:可组装的 JavaScript 和 JSX 检查工具
一句话介绍 ESLint:
- ESLint 是一个插件化的、基于规则的 JavaScript/Typescript/JSX/TSX 代码检查与部分问题修复的工具
ESLint 最大的作用就是规范化你的 js/ts/jsx/tsx 代码。
注:以前有专门用于规范化 ts 代码的工具叫作 TSLint,现在 TSLint 已经不再维护,ts 代码规范化工具被统一到了 ESLint 中
虽然不同项目对 ESLint 配置有不同的需求,但集成的过程以及使用的过程都是完全一致的。
在使用 ESLint 之前,推荐在 IDE 中安装 ESLint 插件,详细流程请查阅:附:IDE 集成 ESLint 插件。
2. 集成 ESLint
2.1 安装 ESLint
首先要安装的就是 eslint 这个包:
npm i eslint -D # npm
yarn add eslint -D # yarn
pnpm i eslint -D # pnpm
依赖安装好之后,即可开始配置 ESLint
2.2 配置 ESLint
ESLint 提供了多种配置方式:
.eslintrc.jspackage.json未设置type字段时使用
.eslintrc.cjspackage.json设置type字段为commonjs或module时使用
.eslintrc.json.eslintrc.yamlpackage.json的 eslintConfig 配置项
比较推荐的两种方式是:
.eslintrc.js- 便于提供类型注解和条件语句
package.json的eslintConfig配置项- 有配置项和规则提示
- 如果有封装专门的 ESLint 规则,配置时只需要简短的3行即可,这3行代码没必要单独放到一个文件中
单独配置文件可以与
package.json的eslintConfig配置项共存。
一个项目里可以有多个 ESLint 配置文件,但同一目录下仅支持一个。
ESLint 配置的优先级:
- 从当前文件所在目录向上查找,ESLint 优先使用最临近的一个配置文件
- 如果查找到项目根目录仍未查找到 ESLint 配置文件,则查找
package.json里的eslintConfig配置项 - 如果
package.json里没有eslintConfig配置项,则使用系统主目录(~/)下的 ESLint 配置文件
如果系统主目录
(~/)下没有配置文件,我也不知道会怎么样 ( ̄< ̄||)。
所以通常都会在项目根目录下编写 ESLint 配置。
以 .eslintrc.js 为例,配置过程如下:
- 在项目根目录下创建
.eslintrc.js文件 - 根据 ESLint 配置,编写适合于当前项目的配置文件
- 文末附上了我汇总的 ESLint 配置文件中每一个配置项的含义
// 推荐的一点配置 module.exports = { root: true, env: { es6: true, node: true, browser: true, }, parserOptions: { sourceType: "module", }, extends: ["eslint:recommended"], plugins: [], rules: { "global-require": "off", "import/no-dynamic-require": "off", "no-console": "warn", "no-debugger": "warn", "spaced-comment": "warn", "comma-style": ["warn", "last"], }, globals: { defineProps: "readonly", defineEmits: "readonly", defineExpose: "readonly", withDefaults: "readonly", }, };
3 补充 ESLint 插件
3.1 Typescript
官方教程推荐:typescript-eslint 官方
大致步骤如下:
-
安装需要的依赖
npm i @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript -D # npm yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript -D # yarn pnpm i @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript -D # pnpm如果是在 Vue3 项目中集成 Typescript 的规则,建议使用
@vue/eslint-config-typescript这个插件,而不是使用@typescript-eslint/eslint-plugin -
补充 ESLint 配置
在之前配置的基础上,额外加上如下配置即可:
module.exports = { // ... 其他配置 parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], // ... 其他配置 };
完成上述基本配置之后,你的项目将不会提示 Typescript 相关的语法错误了。其他更高阶的配置,可参考对应插件的官方文档来配置。
3.2 Vue
官方插件:eslint-plugin-vue
配置步骤:
-
安装依赖
npm i eslint-plugin-vue -D # npm yarn add eslint-plugin-vue -D # yarn pnpm i eslint-plugin-vue -D # pnpm -
补充 ESLint 配置
如果之前补充了 Typescript 的配置,则只需补充如下配置即可:
module.exports = { // ... 其他配置 parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], extends: [ // 'eslint:recommended', // Vue 插件中已经加入这个了,所以不需要再加这个了 'plugin:vue/vue3-recommended', // 如果是 Vue3 项目则开启这个 // 'plugin:vue/recommended' // 如果是 Vue2 项目则开启这个 'plugin:@typescript-eslint/recommended' ], // ... 其他配置 };
按照如上步骤执行之后,通常来说 .vue template 里不会报之前的错误了,但里面的标签还是会报错。
原因是 parser 没有切换,所以更新一下 parser 和 parserOptions 配置即可,更新之后将会是如下:
module.exports = {
// ... 其他配置
parser: 'vue-eslint-parser',
parserOptions: {
parser: "@typescript-eslint/parser",
sourceType: "module"
}
// ... 其他配置
};
vue-eslint-parser 这个 parser 提供了额外的几个 parserOptions 配置属性,可参考 vue-eslint-parser Github 的文档描述。
3.3 React
官方插件:eslint-plugin-react Github
配置步骤:
-
安装依赖
npm i eslint-plugin-react -D # npm yarn add eslint-plugin-react -D # yarn pnpm i eslint-plugin-react -D # pnpm -
补充 ESLint 配置
只需在你的配置文件里加入如下配置即可:
module.exports = { // ... 其他配置 plugins: [ 'react', // ...其他插件 ], extends: [ 'eslint:recommended', 'plugin:react/recommended', // 'plugin:react/jsx-runtime', // 如果使用的 React 17 的新版 JSX transform,就要启用这个 // ...其他规则集合 ], // ... 其他配置 };如果上面的配置不够,就再开启 JSX 支持
module.exports = { // ... 其他配置 parserOptions: { ecmaFeatures: { jsx: true, // ... 其他配置 }, // ... 其他配置 }, // ... 其他配置 };
4. 使用 ESLint
4.1 命令行
ESLint 常用的命令如下:
- 检查 ESLint 结果:
eslint --ext .js,.jsx,.ts,.tsx,.vue src - 修复 ESLint 可修复的错误:
eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src
详细命令可查阅中文文档 ESLint 命令行接口
4.2 结合 lint-staged 使用
在前一篇文章 一、项目规范的基石——husky 与 lint-staged 中详细介绍了如何集成 husky 和 lint-staged,ESLint 集成后,只需在 package.json 中的 lint-staged 配置项中加入 ESLint 的命令即可。如 Vue 项目中会增加如下命令:
{
"lint-staged": {
"*.{js,jsx,vue,ts,tsx}": "eslint --fix"
}
}
附:ESLint 相关资源
ESLint 网站
Sherry Standard ESLint
根据我自己的开发习惯,我封装了自己的 ESLint 配置插件——@sherry-standard/eslint-plugin,这个插件里包含了多个类型的配置,可根据项目实际需要来选择不同的类型,详细可查看对应的文档。
ESLint 部分配置释义
注:这部分的所有代码都总结自 ESLint 中文网:用户指南-配置,如有错误,望指正 ~
注:如需官方的类型定义文件,可安装
@types/eslint来查看。
// eslint.d.ts
/* eslint-disable @typescript-eslint/no-explicit-any */
declare namespace ESLint {
export interface Env {
browser?: boolean; // 浏览器环境中的全局变量
node?: boolean; // Node.js 全局变量和 Node.js 作用域
commonjs?: boolean; // CommonJS 全局变量和 CommonJS 作用域
"shared-node-browser"?: boolean; // Node.js 和 Browser 通用全局变量
es6?: boolean; // 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)
worker?: boolean; // Web Workers 全局变量
amd?: boolean; // 将 require() 和 define() 定义为像 amd 一样的全局变量
mocha?: boolean; // 添加所有的 Mocha 测试全局变量
jasmine?: boolean; // 添加所有的 Jasmine 版本 1.3 和 2.0 的测试全局变量
jest?: boolean; // Jest 全局变量
phantomjs?: boolean; // PhantomJS 全局变量
protractor?: boolean; // Protractor 全局变量
qunit?: boolean; // QUnit 全局变量
jquery?: boolean; // jquery 全局变量
prototypejs?: boolean; // prototypejs 全局变量
shelljs?: boolean; // ShellJS 全局变量
meteor?: boolean; // Meteor 全局变量
mongo?: boolean; // MongoDB 全局变量
applescript?: boolean; // AppleScript 全局变量
nashorn?: boolean; // Java 8 Nashorn 全局变量
serviceworker?: boolean; // Service Worker 全局变量
atomtest?: boolean; // Atom 全局变量
embertest?: boolean; // Ember 全局变量
webextensions?: boolean; // WebExtensions 全局变量
greasemonkey?: boolean; // GreaseMonkey 全局变量
/**
* 支持自定义的环境
* 如果你想在一个特定的插件中使用一种环境,确保提前在 plugins 数组里指定了插件名,
* 然后在 env 配置中不带前缀的插件名后跟一个 / ,紧随着环境名
*/
[key: string]: boolean | undefined;
}
export interface ParserOptions {
/**
* 可以使用 3、5、6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本
* 开启这个配置项时,`不会` 自动启用 ES6 全局变量
*/
ecmaVersion: 3 | 5 | 6 | 7 | 8 | 9 | 10;
/**
* script: 通用 JavaScript 语法
* module: ECMAScript 模块语法
*/
sourceType: "script" | "module";
/**
* 想使用的额外的语言特性,所有配置项都默认为 false
*/
ecmaFeatures: {
/**
* 是否启用 jsx 语法支持
* * 注意:支持 JSX 语法并不等同于支持 React
* * 如果你期望支持 React 语义,可使用 eslint-plugin-react 插件
*/
jsx: boolean;
globalReturn: boolean; // 是否允许在全局作用域下使用 return 语句
impliedStrict: boolean; // 是否在 ecmaVersion 是 5 或更高时,启用全局 strict mode
experimentalObjectRestSpread: boolean; // 一个实验性功能
};
/**
* 支持自定义的任意配置属性
*/
[key: string]: any;
}
/**
* 0 <=> "off" 关闭这条规则
* 1 <=> "warn" 开启这条规则,不会导致程序退出
* 2 <=> "error" 开启这条规则,当被触发的时候,程序会退出
*/
export type RuleValue = "off" | "warn" | "error" | 0 | 1 | 2;
export type RuleOptions = string | number | boolean | symbol;
export interface Rules {
[key: string]: RuleValue | [RuleValue, ...RuleOptions[]];
}
export interface Override {
files: string[];
processor?: string;
/**
* 为指定的文件类型配置 ESLint 规则
*/
rules?: Rules;
}
export interface Config {
/**
* ESLint 一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找
*/
root?: boolean;
/**
* 环境支持配置,所有的配置项默认都为 false
* 这些环境并不是互斥的,所以你可以同时定义多个
*/
env?: Env;
/**
* 默认使用 Esprima 作为解析器
* Esprima @see https://github.com/eslint/espree
* 可自定义解析器
* 解析器必须要满足以下要求:
* * 1. 它必须是一个 Node 模块,可以从它出现的配置文件中加载。通常,这意味着应该使用 npm 单独安装解析器包
* * 2. 它必须符合 parser interface。
* parser interface @see http://eslint.cn/docs/developer-guide/working-with-plugins#working-with-custom-parsers
* 与 ESLint 兼容的 parser:
* Esprima @see https://www.npmjs.com/package/esprima
* Babel-ESLint @see https://www.npmjs.com/package/babel-eslint 一个对Babel解析器的包装,使其能够与 ESLint 兼容
* @typescript-eslint/parser @see https://www.npmjs.com/package/@typescript-eslint/parser 将 TypeScript 转换成与 estree 兼容的形式,以便在ESLint中使用
*/
parser?: string;
parserOptions?: ParserOptions;
/**
* 值为字符串:指定配置的字符串(配置文件的路径、可共享配置的名称、eslint:recommended 或 eslint:all)
* 值为字符串数组:每个配置都继承它前面的配置
* extends 的一个属性值可以由以下内容组成:
* - `plugin:`
* - 包名,如 `prettier`
* - `/`
* - 配置名称 (比如 `recommended`)
* extends 的一个属性值可以是到基本配置文件的绝对路径,也可以是相对路径
*/
extends?: string | string[];
/**
* 插件是相对于 ESLint 进程的当前工作目录解析的
* 插件名称可以省略 eslint-plugin- 前缀,也可携带这个前缀
*/
plugins?: string[];
/**
* 指定统一的处理器
* 处理器的作用:
* 1. 从另一种文件中提取 JavaScript 代码,然后让 ESLint 检测 JavaScript 代码
* 2. 在预处理中转换 JavaScript 代码
* 可以生成命名的代码块,ESLint 将这样的命名代码块作为原始文件的子文件处理
*/
processor?: string;
/**
* 为特定类型的文件指定处理器
*/
overrides?: Override[];
/**
* writable: `允许` 被重新赋值。由于历史原因,布尔值 true 和字符串值 "writeable" 等价于 "writable"
* readonly: `不允许` 被重新赋值。由于历史原因,布尔值 false 和字符串值 "readable" 等价于 "readonly"
* * 虽然但是,不建议使用旧值!
* * 注意:要启用 no-global-assign 规则来禁止对只读的全局变量进行修改
*/
globals?: {
[key: string]: "writable" | "readonly";
};
/**
* 配置定义在插件中的一个规则的时候,必须使用 插件名/规则ID 的形式
* 比如配置 prettier: "prettier/prettier": "warn"
* * 当指定来自插件的规则时,确保删除 eslint-plugin- 前缀
* 比如 prettier 对应的插件 eslint-plugin-prettier
*/
rules?: Rules;
/**
* 共享设置
* 它将提供给每一个将被执行的规则
* 如果你想添加的自定义规则而且使它们可以访问到相同的信息,这将会很有用,并且很容易配置
*/
settings?: {
[key: string]: any;
};
}
}