Skip to content
快速预览

导读

✍️ w 🕒 2023-08-17 00:37:37(9 months ago) 🔗 C.前端工程化

'软件开发需要多人协同'、'不同开发者具有不同的编码习惯和喜好'、'不同的喜好会增加项目的维护成本'、'每个项目或者团队需要明确统一的标准'

因此要形成规范尤其是前端,JS 的弱类型和动态类型,JS 的变量在声明时无需指定其类型。并且在其声明之后,可以为其随便赋值不同的类型。JS 由于不需要关注变量的类型,可以使代码更加简洁,也能使开发者集中更多的精力在处理业务逻辑之上。但由于其无法保证变量类型,从而在程序运行期可能发生跟类型相关的错误。 比如:

js
var s = 1
s() //Uncaught TypeError: s is not a function

而这样的错误对于 JAVA 在编译期间就会检查出来。为了可以在编写中发现问题,前端出现了很多种尝试类似'TypeScript、CoffeeScript 或 Elm' 辅助工具出现了'Lint''Lint'工具最早是使用于 UNIX 系统中 C 语言的程式码静态分析工具,主要是用来标记语法结构上有可疑的、濳在的问题语法或指令,在前端类似的这种类似工具有'JSLint 与 JSHint',随着时代推移'ESLint'由 Nicholas C. Zakas 创造,正如是为 ES 新标准语法所设计,相比其他 js 检查工具来说'ESLint'的功能具有

  • 有更多规则选项可以依需求或喜好设定
  • 函式库或框架的开发者可以依需求再开发扩充
  • 支持更高的 es 语法和实验特性和 JSX 语法
  • 提供错误警告

正是因为 ESlint (使用 Node.js 编写) 需要将源码转为 AST 的特点并且还可以扩展规则,默认的解析器也能替换,这种自由度高可插拔的形式,最后'ESLint' 成为现阶段'js' 代码质量检查的工具

帮助解决问题

  • '语言语法检查':比如检查出字符串引号或者函数调用括号没有匹配等问题。
  • '编码错误检查':比如检查出开发者在使用一个不存在的变量或者变量定义了却没有使用等问题。
  • '代码风格检查':比如检查出开发者没有使用分号(与所选风格有关)等问题。

注意他不会检查你 js api 调用的是否正确,明确他能做的

安装使用

bash
npm install eslint -D

通过 npx 可以产看'eslint' 版本

bash
npx eslint --version

安装后开始使用:

初始化生成配置文件 npx eslint --init 初始化的时候会询问几个问题:

问题 1 : 如何使用 ESLint ? 只检查语法错误 | 检测语法错误以及问题代码 | 检测语法错误以及问题代码以及代码风格

问题 2: 你的项目模块化选择类型? JS modules(import/export) | CommonJS(require/exports) | None of these

问题 3:项目使用框架 问题 4: 是否使用 TS 问题 5: 运行环境 Browser | Node

问题 6: 定义代码风格 主流代码风格 | 个人自定义 | 根据代码判断

问题 7:配置文件格式 JS | YARM | JSON 问题 8: 安装额外的插件 Y

安装完成后会出现.eslintrc.js 文件,除了 .eslintrc.js 配置外还有其他配置文件的声明写法

  • 'JavaScript' - 使用 .eslintrc.js 然后输出一个配置对象。
  • 'YAML' - 使用 .eslintrc.yaml 或 .eslintrc.yml 去定义配置的结构。
  • 'JSON' - 使用 .eslintrc.json 去定义配置的结构,ESLint 的 JSON 文件允许 JavaScript 风格的注释。
  • 'package.json' - 在 package.json 里创建一个 eslintConfig 属性,在那里定义你的配置。

优先级 '.eslintrc.js' > '.eslintrc.yaml' >'.eslintrc.yml' >'.eslintrc.json' >'.eslintrc'> 'package.json'

也可以使用 eslintignore 忽略指定文件,对于一些公共的 js,或者测试脚本,不需要进行检测,我们可以通过在项目根目录创建一个.eslintignore告诉 ESLint 去忽略特定的目录或者文件

根据上面的询问选好配置后:

  • 'npx eslint [文件路径]' -- 检查对应文件中编码格式。路径可以使用路径通配符
  • 'npx eslint [文件路径] --fix' -- 自动修正代码风格

eslint 检查指令 案例

bash
# 检测单个文件
npx eslint file1.js file2.js
# 检测src和scripts目录
npx eslint src scripts
js
var a = '1'
const zz = '1000'

检查对应文件中编码格式 给出了错误原因

检查并修复 fix

--fix后缀,是 ESLint 提供自动修复基础错误的功能,它只能修复一些基础的不影响代码逻辑的错误,比如代码末尾加上分号、表达式的空格等等。例如 npx eslint src scripts --fix / npx eslint file1.js file2.js --fix

案例

js
var a = '1'
    const zz = '1000'

修复后

js
const a = '1';
const zz = '1000';

如图修复了格式问题 但并没有修复未引用问题

指定文件ext

eslint 修复和检查都可以指定具体文件或者具体文件夹,例如可以指定具体文件'aa.vue','aa.js',但是指定文件时候例如'/src' 这个文件下会有各种文件类型,但eslint 默认只会检测文件夹中的'js' 文件,此时需要使用'ext'

注意只有在指定是文件夹时候使用'ext' 才会生效,举个例子npx eslint --ext .js,.jsx,.vue src

eslintignore 忽略指定文件

对于一些公共的js,或者测试脚本,不需要进行检测,我们可以通过在项目根目录创建一个.eslintignore告诉ESLint去忽略特定的目录或者文件

yaml
node_modules/
**/*.spec.*
**/style/
*.html
/components/test/*
es/
lib/
_site/
dist/
components/version/version.tsx

配置文件的字段说明

  • parser: 解析器是ESLint用于将代码转换为抽象语法树(AST)的组件。ESLint默认使用的解析器是Espree,它能够将编写的代码解析成抽象语法树的形式,以便ESLint可以根据规则对代码进行验证和分析。

  • extends: extends字段用于递归地扩展ESLint的配置。通过指定一个配置文件或一个可共享的配置名称,可以继承和重用其他配置。这样可以方便地在项目中共享和继承一组预定义的规则和配置,提高代码的一致性和可维护性。

  • rules: rules字段用于定义ESLint的规则,它允许您自定义代码的静态分析规则。您可以为不同的规则指定不同的错误级别(如警告或错误)或禁用特定的规则。通过配置rules字段,您可以覆盖继承的配置或添加自定义规则,以满足项目的特定需求。

  • parserOptions: parserOptions字段用于配置解析器的选项。您可以在这里指定解析器的版本、支持的ECMAScript版本、启用特定的语言特性(如模块化)等。解析器选项的配置可以影响ESLint在解析和分析代码时的行为。

  • plugins: plugins字段用于为ESLint添加额外的检查规则。ESLint的核心规则集并不包含所有可能的规则,但通过使用插件,您可以扩展ESLint并使用来自插件的规则。插件可以提供特定领域的规则(如React或Vue.js),或者是一些通用的规则扩展。

  • env: env字段用于定义一组预定义的全局变量,表示代码运行的环境。例如,如果您的代码将在浏览器环境中执行,您可以将env字段设置为{ "browser": true },以便ESLint知道在分析代码时应该考虑浏览器全局变量。通过配置env字段,可以避免对未声明的变量和全局对象的使用进行警告或错误的检查。

root

js
module.exports = {
  root: true,
  // others
};

root:是否以当前目录为根目录。 告诉 ESLint 不要再往上级目录查找,利用此属性配置,项目级和目录级的配置都可以不受上级目录以及祖先目录的配置影响,通常项目根目录应该设置为 true 。

举个例子,比如这个项目 vue-project1,默认情况下 root 为 false,而且该项目上层目录下还有 eslint 配置文件的话,这个更上一层的配置就会对你的项目文件的代码产生作用,直到到达根目录才会停止。这是我们不愿意看到的,所以就需要我们在当前项目目录下设置 root: true,告诉 ESLint 这里就是根目录了,别再往上查找其他的配置文件了!

parser -- 解析器

想成为eslint 的parser解析器需要满足两点

  • 它必须是一个 Node 模块,应该使用 npm 单独安装解析器包.
  • 它必须符合 parser interface

其他解析器:

  • esprima: ESLint最初使用的解析器,但后来不再维护。
  • espree: ESLint基于esprima v1.2.2开发的解析器,成为ESLint的默认解析器。
  • babel-eslint: 是对Babel解析器的封装,使其与ESLint兼容。
  • @babel/eslint-parser: 从v11.xx版本开始,babel-eslint不再维护和更新,取而代之的是@babel/eslint-parser
  • @typescript-eslint/parser: 将TypeScript代码转换为与estree兼容的形式,以便在ESLint中使用。

解析器的选择:

  • 如果使用TypeScript,应选择@typescript-eslint/parser作为解析器。
  • 如果使用ES中的实验性属性,可以使用babel提供的解析器。
  • 若要支持最新的ES标准语法,可以使用ESLint默认的解析器。

解析器配置示例:

  • 配置示例(包含TypeScript解析器):

    javascript
    module.exports = {
      parser: '@typescript-eslint/parser',
      // 其他配置项...
    };
  • 配置示例(使用babel解析器):

    javascript
    module.exports = {
      parser: 'babel-eslint',
      // 其他配置项...
    };
  • 配置示例(不指定解析器,默认使用espree):

    javascript
    module.exports = {
      // 其他配置项...
    };

针对Vue.js和TypeScript的配置:

  • 在Vue.js项目中结合TypeScript时,可以使用@vue/eslint-config-typescript扩展配置,它已经包含了TypeScript解析器和相关规则。
  • 可以参考以下示例配置:
    javascript
    module.exports = {
      root: true,
      'extends': [
        'plugin:vue/vue3-essential',
        'eslint:recommended',
        '@vue/eslint-config-typescript',
        '@vue/eslint-config-prettier/skip-formatting'
      ],
      parserOptions: {
        ecmaVersion: 'latest'
      },
      // 其他配置项...
    };

根据具体需求和项目配置,选择合适的解析器和配置,以正确解析和检查代码。 你使用@babel/eslint-parser 遇到了麻烦参考 Updating babel-eslint to @babel/eslint-parser for React apps

parserOptions -- 解析器选项

解析器选项用于配置解析器的行为,以便正确解析和分析代码。解析器选项的配置可以影响ESLint在解析和分析代码时的行为。

可以使用解析器选项覆盖该设置以启用对其他 ECMAScript 版本以及 JSX 的支持。简单理解配合你的解析器,之前说过默认的解析器是'espree'去gitub 搜索你可以发现当传入不同参数的时候配置器将会有不同的结果返回。

如果你正在尝试新的一些'ES'语法中的实验属性使用'babel' 提供的解析,当然如果你仅仅是想支持最新的最终 ES 标准可以使用eslint 默认以目前写文章的节点装饰器为例属于一个实验属性,在使用默认的eslint的解析器 是不行的,你需要使用'babel'

需要安装 解释一下'decorators' 装饰器目前在第二阶段因此需要下载'babel' 插件,关于配置

bash
npm install @babel/core @babel/eslint-parser @babel/plugin-proposal-decorators  --save-dev
js
module.exports = {
        "parser":"@babel/eslint-parser",
        "env": {
            "browser": true,
            "es2021": true,
            "node": true
        },
        "extends": "eslint:recommended",
        // 相当于配置@babel/eslint-parser 解析器的配置
        parserOptions: {
            // 如果你 没有写 类似.babelrc 将需要requireConfigFile设置fasle
            // 表示不使用配置文件
            requireConfigFile: false,
            // 因为没有配置类似.babelrc 所以需要配置babelOptions声明使用的插件
            babelOptions: {
                plugins: [["@babel/plugin-proposal-decorators",{"legacy": true}]],
            }
        },
        "rules": {
        }
    };

这个案例中如果你配置了类似'.babelrc' 文件那么你就可以不用配置'parserOptions' 这个参数

plugins -- 插件

plugin插件主要是为eslint新增一些检查规则,ESLint 虽然可以定义很多的 rules,只是检查 JS 语法。如果需要检查 Vue 中的 template 或者 React 中的 jsx,就束手无策了。引入插件的目的就是为了增强 ESLint 的检查能力和范围简单的说像vue react 这类新的框架会有自己的规则,这类规则需要去安装额外的插件

在使用插件的用法上 插件名称可以省略 'eslint-plugin- 前缀'

js
{
    "plugins": [
        "plugin1", // eslint-plugin-plugin1的简写
        "eslint-plugin-plugin2"
    ]
  }

如果仅配置"plugins": ["vue"],vue文件中template内容还是会解析失败。这是因为不管是默认的espree还是babel-eslint解析器都无法解析.vue中template的内容;eslint-plugin-vue插件依赖vue-eslint-parser解析器,而vue-eslint-parser解析器只会解析template内容,不会检测script中的JS内容,因此我们还需要指定一下解析器:

js
{
    "extends": ["eslint:recommended"],
    "plugins": ["vue"],
    "parser": "vue-eslint-parser",
    "parserOptions": {
        "parser": "babel-eslint",
        "ecmaVersion": 12,
        "sourceType": "module",
    },
}

上面parserOptions.parser看的有点迷糊,这是由于外层的解析器只能有一个,我们已经用了vue-eslint-parser就不能再写其他的;因此vue-eslint-parser的做法是在解析器选项中再传入一个解析器选项用来处理script中的JS内,相当于此时有两个解析器在工作

rules -- 规则

规则的校验说明,有 3 个报错等级

  • 'off 或 0':关闭对该规则的校验;
  • 'warn 或 1':启用规则,不满足时抛出警告,且不会退出编译进程;
  • 'error 或 2':启用规则,不满足时抛出错误,且会退出编译进程;
  • 通常规则只需要配置开启还是关闭即可;但是也有些规则可以传入属性,比如:
json
{
		rules: {
				'quotes': ['error', 'single'],  // 如果不是单引号,则报错
				'one-var': ['error', {
						'var': 'always',  // 每个函数作用域中,只允许 1 个 var 声明
						'let': 'never',   // 每个块作用域中,允许多个 let 声明
						'const': 'never', // 每个块作用域中,允许多个 const 声明
				}]
		}
}

通过 rules 单独配置的规则优先级比 extends 高,关于规则像在'extends ' 中介绍的根据开头找到他的组织去看他的规则都有哪些可以自己配置

也可以在文件中指定规则,主要注释要使用 /**/ 形式,并且 eslint + 规则 + 等级,下面例子就是'no-var' 是不准使用var 的规则,error 就是使用了要报错的等级

js
/* eslint no-var: error */
var a = '1'

更多规则:

js
/* eslint-disable */ -- '该注释放在文件顶部,eslint不会检查整个文件'
/* eslint-enable */ -- '重新启用eslint检查'
/* eslint-disable eqeqeq */'只禁止某一个或多个规则'
/* eslint-disable-next-line */'下一行禁止eslint检查'
// eslint-disable-line  '当前行禁止eslint检查'

extends -- 继承

在配置 ESLint 规则时,从零开始配置是一件麻烦的事情,但是可以通过引用其他已经配置好的完整规则文件来简化配置过程。以下是一些常用的规则文件选项:

  • "eslint:recommended":启用 ESLint 推荐的规则,具体开启的规则可以在此处查看。

  • "eslint:all":开启 ESLint 中所有核心规则。

另外,还可以在初始化 ESLint 时提供以下三种选择:

  • 'Google标准':安装 'npm install eslint-config-google -g'。

  • 'Airbnb标准':安装依赖 'eslint-plugin-import, eslint-plugin-react, and eslint-plugin-jsx-a11y' 等插件。如果想查看具体的依赖项,可以执行指令 'npm info "eslint-config-airbnb@latest" peerDependencies'。

  • 'Standard标准':一些前端工程师自定义的标准,安装执行 'npm install eslint-config-standard eslint-plugin-standard eslint-plugin-promise -g'。

extends 属性的值可以由以下几部分组成:

  • eslint: 开头的是 ESLint 官方扩展,有两个常用选项:eslint:recommended(推荐规范)和 eslint:all(所有规范)。

  • plugin: 开头的是插件类型的扩展。用于引入特定插件的规则和功能。这些插件扩展了 ESLint 的功能,提供了针对特定语言、框架或库的规则,以及其他辅助功能。

  • eslint-config: 开头的来自 npm 包的扩展,使用时可以省略 eslint-config-。例如,可以直接写成 standard

  • @ 开头的扩展和 eslint-config 类似,是在 npm 包上加了一层作用域 scope。

以下是一个示例,后面的规则会覆盖前面的规则:

json
{
  "extends": [
    "eslint:recommended", // 使用 ESLint 推荐规范
    "airbnb", // 相当于使用 eslint-config-airbnb
    "plugin:vue/essential", // Vue 必不可少的类型规则
    "eslint-config-airbnb-base/rules/strict" // 指定一个具体文件地址
  ]
}

社区封装的 ESLint 插件在 npm 上搜索 eslint-plugin- 可以发现许多社区封装的 ESLint 插件,其中一些比较出名的插件有:

  • eslint-plugin-react:用于 React 相关规则的插件。
  • eslint-plugin-import:用于导入规则的插件。

这些插件的出现是因为 ESLint 自带的规则只包含 ES 语法本身的规则,而像 Vue、React 等内置的规则并不包含在其中。以 Vue 为例,可以通过以下方式扩展规则:

json
"extends": [
  "plugin:vue/base", // 基础
  "plugin:vue/essential", // 必不可少的
  "plugin:vue/recommended", // 推荐的
  "plugin:vue/strongly-recommended" // 强烈推荐
]

如果 extends 配置是一个数组,那么最终会将所有规则项进行合并。当出现冲突时,后面的规则会覆盖前面的规则。

env -- 环境

举个例子当我们在项目使用了 浏览器环境全局变量'window','node 环境global','jquery $',这些某种环境特带的让eslint 知道不是我们用错了而是这类东西是某环境下的

es6 中除了模块之外的其他特性,同时将自动设置 parserOptions.ecmaVersion 参数为 6以此类推 ES2017 是 8,而 ES2021 是 12(parserOptions.ecmaVersion 关于它可以看parserOptions)

json
{
  "env": {
    "browser": true, // 项目中有代码在浏览器环境运行
    "node": true, // 项目中有代码在 Node.js 环境下运行
    "es6": true // 启动 ES6 全局变量和类型,同时会自动设置解析器为ES6
  }
}

globals -- 全局变量

ESLint会检测未声明的变量,并发出报错,比如node环境中的process,浏览器环境下的全局变量console,以及我们通过cdn引入的jQuery定义的$等;我们可以在globals中进行变量声明

但是node或者浏览器中的全局变量很多,如果我们一个个进行声明显得繁琐,因此就需要用到我们的env,这是对环境定义的一组全局变量的预设,可以参考下面'env' 字段

json
{
    "globals": {
        // true表示该变量可读写,false表示变量是只读
        "$": true,
        "console": false
    }
}

overrides -- 覆盖

当使用 ESLint 配置文件时,overrides 选项允许你为特定的文件、目录或 glob 模式应用特定的 ESLint 配置。这样,你可以根据需要为不同的代码部分指定不同的规则。

overrides 是一个数组,每个数组元素都是一个对象,表示一个覆盖配置。每个覆盖配置对象具有以下属性:

  • files:一个字符串或字符串数组,用于指定要应用规则的文件、目录或 glob 模式。可以使用通配符 * 匹配文件名,或者使用 ** 匹配任意层级的目录。例如,"src/*.js" 匹配 src 目录下的所有 .js 文件,"src/**/*.js" 匹配 src 目录及其子目录下的所有 .js 文件。

  • excludedFiles:一个字符串或字符串数组,用于指定要排除的文件、目录或 glob 模式。这些文件将不会受到覆盖配置的影响。同样,可以使用通配符 *** 进行匹配。

  • extends:一个字符串或字符串数组,表示要应用的规则集或配置。可以是 ESLint 内置的规则集,也可以是自定义的配置。例如,"eslint:recommended" 表示使用 ESLint 内置的推荐规则集,"my-config" 表示使用自定义的配置文件。

  • rules:一个对象,用于指定要覆盖或添加的规则。你可以在这里覆盖全局配置中的规则,或者添加新的规则。例如,{"no-console": "off"} 表示禁用 no-console 规则。

  • plugins:一个字符串数组,用于指定要使用的插件。你可以在这里列出你想要使用的插件,然后在规则中使用插件提供的规则。

通过使用 overrides,你可以根据文件类型、目录结构或其他条件,为不同的代码部分应用不同的规则和配置,以满足项目的特定需求。

举个例子场景: 当使用 ESLint 进行代码检查时,overrides 选项允许你为不同的文件或文件类型应用不同的代码规则。

假设你正在开发一个 Web 应用程序,其中包括前端代码和后端代码。前端代码使用 JavaScript 编写,后端代码使用 Node.js 编写。你可能希望为这两部分代码应用不同的代码规则,因为它们具有不同的用途和要求。

在这种情况下,你可以使用 overrides 来创建两个不同的配置,每个配置针对特定的代码部分:

对于前端代码,你可以定义一个覆盖配置,指定应该应用哪些规则以及如何进行代码检查。你可能希望使用一些与浏览器兼容性、前端最佳实践等相关的规则。

对于后端代码,你可以定义另一个覆盖配置,针对 Node.js 环境应用不同的规则。你可能希望关注一些与服务器端开发、安全性等相关的规则。

使用 overrides,你可以根据文件路径、文件名模式或其他条件来定义这些覆盖配置。这样,当运行 ESLint 时,它将根据文件类型自动应用相应的规则。

通过这种方式,你可以根据不同的代码部分的需要,更精细地定义代码规范和代码质量要求,从而提高代码的可读性、可维护性和一致性。

案例说明,其中 overrides 中的规则会覆盖全局的规则,但是如果overrides 中的规则没有指定,那么全局的规则将会被继承,在 overrides 数组中的规则会按照从上到下的顺序依次应用配置,直到找到与当前文件匹配的覆盖配置为止。

js
module.exports = {
  rules: {
    "no-console": "warn",
  },
  overrides: [
    {
      files: ["src/**/*.js"],
      rules: {
        "no-console": "off",
      },
    },
    {
      files: ["test/**/*.js"],
      rules: {
        "no-console": "error",
      },
    },
  ],
};

plugins 和 extends 中 plugin区别

'plugins' 理解成扩展校验规则,即原本'eslint' 是为了'js'出现的,随着前端的发展,出现一些其他格式文件例如'vue',此时eslint 这种可插拔设计,在'plugins' 扩展将其检测规则扩展到eslint

规则就像是一个集合,真正想使用什么规则需要人为去配置,这种配置可以使用'rules' 一条一条的去指定,当然也可以使用一组配置开启集合这个就是'extends ' 字段

js
module.exports = {
      plugins: [
        'eslint-plugin-react' // 扩展的规则
      ],
      extends: [
            // 新提供的规则一个开启的配置集合
            'eslint-plugin-react/recommended'
        ],
      rules: {
        'eslint-plugin-react/jsx-boolean-value': 2 // 如果没有eslint-plugin-react/recommended需要自己慢慢配置
      }
    }

一个整体的配置

如果要检测 React 项目中的 JSX 语法,给 ecmaFeatures 添加 jsx: true 是不推荐的,要用专门的 eslint-plugin-react 。

js
// .eslintrc.js

module.exports = {
  env: { // 标记当前代码最终的运行环境
    browser: true, // 代码运行在浏览器环境
    es2020: true 
  },
  // 语法解析器配置ts 语法需要自己的语法解析器因此要声明
  // parser: '@typescript-eslint/parser',
  extends: [ // 记录共享配置类似继承的概念,下面的意思是使用node_modules  模块安装的'standard'检查作为模板
    'standard' // 如果需要在多个项目共享一个eslin配置,可以定义一个公共配置文件并在此集成
// 继承规则配置 不需要单独配置开关
    'plugin:react/recommended'
  ],
  parserOptions: { // 设置语法解析器的相关配置 控制是否允许使用某一个ES版本的语法
    ecmaVersion: 11
  },
  rules: { // 配置eslint中每一个校验规则的开启/关闭
    'no-alert': "error" // 内置规则名称: off/warn/error
    // // 2 - ERROR  该规则解决React未使用错误
    // 'react/jsx-uses-react': 2
  },
 // plugins: [
  //   // eslint-plugin-react 插件
  //   'react'
  //   '@typescript-eslint'
  // ]
  global: { // 额外声明代码中可使用全局成员 最新版本默认配置已不再体现
    // 例如要使用jQuery对象
    "jQuery": "readonly"
  }
}

参考

eslint 官网

从 ESLint 开始,说透我如何在团队项目中基于 Vue 做代码校验

eslint 配置文件 -- .eslintrc

eslint 配置文件 -- .eslintrc

内容非常详细!领略Eslint代码检查的四种姿势

Updating babel-eslint to @babel/eslint-parser for React apps

Released under the MIT License.