jieye の 数字花园

Search

Search IconIcon to open search

ESLint

Last updated Nov 1, 2021

# 关于 ESLint

关于 ESLint,它的 Slogan 是 Find and fix problems in your JavaScript code。如上文所说,它可以发现并修复你 JavaScript 代码中的问题。来看一下官网上描述 ESLint 具备的三个特性:

基于以上描述,我们在前端工程化中可以这样使用 ESLint:

  1. 基于业界现有的 ESLint 规范和团队代码习惯定制一套统一的 ESLint 代码规则
  2. 将统一代码规则封装成 ESLint 规则包接入
  3. 将 ESLint 接入脚手架、编辑器以及研发工作流中

# 快速上手

先简单介绍一下如何使用 ESLint,如果已经有所了解的同学,可以直接跳过这一节。

新建一个包含 package.json 的目录(可以在空目录下执行 npm init -y),新建一个 index.js

1
2
// index.js
const name = 'axuebin'

安装 eslint

1
npm install eslint --save-dev

然后执行 ./node_modules/.bin/eslint --init 或者 npx eslint --init 生成一个 ESLint 配置文件 .eslintc.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
module.exports = {
  env: {
    es2021: true,
  },
  extends: 'eslint:recommended',
  parserOptions: {
    ecmaVersion: 12,
  },
  rules: {},
};

生成好配置文件之后,就可以执行 ./node_modules/.bin/eslint index.js 或者 npx eslint index.js 命令对文件进行检查。结果如下: 图片index.js 中的代码命中了 no-unused-vars 这个规则,默认情况下,这个规则是会报 error 的,也就是 ESLint 不允许代码中出现未被使用的变量。这是一个好习惯,有利于代码的维护。

# 简单配置

我们来尝试配置 ESLint 的检查规则。以分号和引号举例,现在你作为团队代码规范的指定人,希望团队成员开发的代码,都是单引号带分号的。

打开 .eslintrc.js 配置文件,在 rules 中添加相关配置项:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
module.exports = {
  env: {
    es2021: true,
  },
  extends: 'eslint:recommended',
  parserOptions: {
    ecmaVersion: 12,
  },
  rules: {
    semi: ['error', 'always'],
    quotes: ['error', 'single'],
  },
};

然后我们将 index.js 中的代码改成:

1
2
// index.js
const name = "axuebin"

执行 eslint 命令之后: 图片可以看到检查结果如下:

老老实实地按照规范修改代码,使用单引号并将加上分号。当然,如果你们希望是双引号和不带分号,修改相应的配置即可。

具体各个规则如何配置可以查看: https://eslint.org/docs/rules[2]

# 自动修复

执行 eslint xxx --fix 可以自动修复一些代码中的问题,将无法自动修复的问题暴露出来。比如上文中提到的引号和分号的问题,就可以通过 --fix 自动修复,而 no-unused-vars 变量未使用的问题,ESLint 就无法自动修复。 图片

# 使用配置包

init 生成的配置文件中,我们看到包含这一行代码:

1
2
3
module.exports = {
  extends: "eslint:recommended"
}

这一行代码的意思是,使用 ESLint 的推荐配置。extends: 'xxx' 就是 继承,当前的配置继承于 xxx 的配置,在此基础上进行扩展。

因此,我们也可以使用任意封装好的配置,可以在 NPM上或者 GItHub上搜索 eslint-config 关键词获取,本文我们将这类封装好的配置称作 “配置集”。比较常见的配置包有以下几个:

# 多人合作最佳实践

简单了解完 ESLint 之后,对于 ESLint 的更多使用细节以及原理,在本篇文章就不展开了,感兴趣的朋友可以在官网详细了解。本文重点还是在于如何在团队工程化体系中落地 ESLint,这里提几个最佳实践。

# 抽象配置集

对于独立开发者以及业务场景比较简单的小型团队而言,使用现成、完备的第三方配置集是非常高效的,可以较低成本低接入 ESLint 代码检查。

但是,对于中大型团队而言,在实际代码规范落地的过程中我们会发现,不可能存在一个能够完全符合团队风格的三方配置包,我们还是会在 extends 三方配置集的基础上,再手动在 rules 配置里加一些自定义的规则。时间长了,有可能 A 应用和 B 应用里的 rules 就不一样了,就很难达到统一的目的。

这时候,就需要一个中心化的方式来管理配置包:根据团队代码风格整理(或者基于现有的三方配置集)发布一个配置集,团队统一使用这个包,就可以做到中心化管理和更新

除此之外,从技术层面考虑,目前一个前端团队的面对的场景可能比较复杂。比如:

以上问题在真实开发中都是存在的,所以在代码规范的工程化方案落地时,一个单一功能的配置集是不够用的,这时候还需要考虑这个配置集如何抽象。

为了解决以上问题,这里提供一种解决方案的思路: 图片具体拆解来看,就是有一个类似 eslint-config-standard 的基础规则集(包括代码风格、变量相关、ES6 语法等),在此基础之上集成社区的一些插件(Vue/React)等,封装成统一的一个 NPM Package 发布,消费时根据当前应用类型通过不同路径来 extends 对应的配置集。

这里有一个 Demo,感兴趣的朋友可以看一下:eslint-config-axuebin[5]

# 开发插件

ESLint 提供了丰富的配置供开发者选择,但是在复杂的业务场景和特定的技术栈下,这些通用规则是不够用的。ESLint 通过插件的形式赋予了扩展性,开发者可以自定义任意的检查规则,比如 eslint-plugin-vue / eslint-plugin-react 就是 Vue / React 框架中使用的扩展插件,官网也提供了相关文档[6]引导开发者开发一个插件。

一般来说,我们也不需要开发插件,但我们至少需要了解有这么个东西。在做一些团队代码质量检查的时候,我们可能会有一些特殊的业务逻辑,这时候 ESLint 插件是可以帮助我们做一些事情。

这里就不展开了,主要就是一些 AST 的用法,照着官方文档就可以上手,或者可以参考现有的一些插件写法。

# 脚手架 / CLI 工具

当有了团队的统一 ESLint 配置集和插件之后,我们会将它们集成到脚手架中,方便新项目集成和开箱即用。但是对于一些老项目,如果需要手动改造还是会有一些麻烦的,这时候就可以借助于 CLI 来完成一键升级。

本文结合上文的 Demo eslint-config-axuebin[7],设计一个简单的 CLI Demo。由于当前配置也比较简单,所以 CLI 只需要做几件简单的事情即可:

核心代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const path = require('path');
const fs = require('fs');
const chalk = require('chalk');
const spawn = require('cross-spawn');

const { askForLanguage, askForFrame } = require('./ask');
const { eslintrcConfig, needDeps } = require('./config');

module.exports = async () => {
  const language = await askForLanguage();
  const frame = await askForFrame();

  let type = language;
  if (frame) {
    type += `/${frame}`;
  }

  fs.writeFileSync(
    path.join(process.cwd(), '.eslintrc.js'),
    `// Documentation\n// https://github.com/axuebin/eslint-config-axuebin\nmodule.exports = ${JSON.stringify(
      eslintrcConfig(type),
      null,
      2
    )}`
  );

  const deps = needDeps.javascript;
  if (language === 'typescript') {
    deps.concat(needDeps.typescript);
  }
  if (frame) {
    deps.concat(needDeps[frame]);
  }

  spawn.sync('npm', ['install', ...deps, '--save'], { stdio: 'inherit' });
};

可运行的 CLI Demo 代码见:axb-lint,在项目目录下执行:axblint eslint 即可,如图: 图片

# 自动化

配置了 ESLint 之后,我们需要让开发者感知到 ESLint 的约束。开发者可以自己运行 eslint 命令来跑代码检查,这不够高效,所以我们需要一些自动化手段来做这个事情。当然 在开发时,编辑器也有提供相应的功能可以根据当前工作区下的 ESLint 配置文件来检查当前正在编辑的文件,这个不是我们关心的重点。

一般我们会在有以下几种方式做 ESLint 检查:

这里提一下 pre-commit 的方案,在每一次本地开发完成提交代码前就做 ESLint 检查,保证云端的代码是统一规范的。

这种方式非常简单,只需要在项目中依赖 husky[9] 和 lint-staged[10] 即可完成。安装好依赖之后,在 package.json 文件加入以下配置即可:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": "eslint --cache --fix"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }
}

效果如图所示: 图片如果代码跑 ESLint 检查抛了 Error 错误,则会中断 commit 流程: 图片这样就可以确保提交到 GitHub 仓库上的代码是统一规范的。(当然,如果认为将这些配置文件都删了,那也是没办法的)

# 个人使用保存时自动统一代码风格

先通过一些简单的配置,然后:

# 配置

  1. 安装VsCode的EsLintvetur插件

  2. 为项目安装EsLint包:

    image-20210501020908564

注意要安装在开发环境上,还有就是如果你使用的是脚手架的话,选了Eslint选项,会自带这些包。

  1. 在项目的根目录下添加.eslintrc.js

    用于校验代码格式,根据项目情况,可自行编写校验规则:

1
2
3
module.exports = {
    // Eslint规则
}
  1. 选项设置

    将下面这部分放入首选项设置中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
"eslint.autoFixOnSave": true,  //  启用保存时自动修复,默认只支持.js文件
"eslint.validate": [
    "javascript",  //  用eslint的规则检测js文件
    {
        "language": "vue",   // 检测vue文件
        "autoFix": true   //  为vue文件开启保存自动修复的功能
    },
    {
        "language": "html",
        "autoFix": true
    },
],

想了解更多的话,推荐看一下VsCode的 EsLint插件

大功告成:

点开文件,你可能会看到如下报错,无需一个一个去改,只要保存一下文件,就可以自动修复这些代码格式上的问题了。

注意:

如果整个文件都飘红的话,不会一次性修改如果的格式问题,会一下改一部分,你可能需要多按几次保存。

# 一键修复项目格式问题:

遇到下面这两种情况:

你可以像下面这样,在package.json里面的scripts里面新增一条如下命令:

1
"lint": "eslint --ext .js,.vue src --fix"

image-20210501021229766

--ext后面跟上的.js.vue是你要检测文件的后缀,.vue后面的src是要检测的哪个目录下面的文件。

--fix的作用是自动修复根据你配置的规则检测出来的格式问题

一键修复

输入如下命令行,就可以自动修复你src文件夹下面的所有根据你配置的规则检测出来的格式问题

1
npm run lint

# .eslintignore 不检测一些文件

在项目的根目录创建一个.eslintignore文件,用于让EsLint不检测一些文件。

比如引的一些别人的文件,插件等,比如文件中:

1
2
src/test/* 
src/test2/* 

文件中的内容像上面这样写,这里第一行是不检测src目录下的test文件夹下面的所有文件。

# 自定义规则

1
2
3
4
5
6
7
8
// .eslintrc.js文件
module.exports = {
    "rules": { // 自定义规则
        "no-console": 0,
        "no-const-assign": 1, 
        "no-extra-bind": 2,
    }
}

0、1、2的意思: