Bootstrap

ESLint 使用教程(六):从输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作

系列文章

ESLint 使用教程(一):从零配置 ESLint
ESLint 使用教程(二):一步步教你编写 Eslint 自定义规则
ESLint 使用教程(三):12个ESLint 配置项功能与使用方式详解
ESLint 使用教程(四):ESLint 有哪些执行时机?
ESLint 使用教程(五):ESLint 和 Prettier 的结合使用与冲突解决
ESLint 使用教程(六):从输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作
ESLint 使用教程(七):ESLint还能校验JSON文件内容?
ESLint 使用教程(八):提高 ESLint 性能的24个实用技巧
代码整洁之道:在 React 项目中使用 ESLint 的最佳实践
代码整洁之道:在 Vue 项目中使用 ESLint 的最佳实践


前言

ESLint 是现代 JavaScript 开发中不可或缺的代码质量工具。它能够帮助开发者找到并修复代码中的问题,提升代码的可维护性。但是,你可能会好奇:从我们在终端里输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作?本文将深入探讨 ESLint 的工作机制。

工作流程

1. 初始化阶段

当我们在命令行里执行 eslint 命令时,ESLint 首先会进行初始化,这个过程主要包括以下几个步骤:

  1. 加载配置文件
    ESLint 会自动查找并加载配置文件,如 .eslintrc.json 或 package.json 中的 eslintConfig 字段。这些配置文件定义了 ESLint 的规则、环境和插件等信息。
{
  "env": {
    "browser": true,
    "node": true
  },
  "extends": "eslint:recommended",
  "rules": {
    "eqeqeq": "warn",
    "curly": "error"
  }
}
  1. 解析命令行参数
    ESLint 会解析你在命令行中传递的参数,例如指定要检查的文件或目录、是否自动修复(–fix)等。
  2. 查找插件和扩展
    ESLint 会查找并加载你在配置文件中指定的插件和扩展(例如 eslint-plugin-react 或 eslint-config-airbnb)。这些插件和扩展能够添加自定义的规则和配置,帮助你更好地管理你的代码风格。

2. 文件读取与解析

初始化完成后,ESLint 开始处理指定的文件。这个过程包括以下步骤:

  1. 读取文件内容
    ESLint 会读取你指定的代码文件。这些文件可以是单个文件,也可以是目录中的所有文件。ESLint 会确保读取到的文件都是需要检查的 JavaScript 文件。ESLint 会读取每一个要检查的文件的内容,并将其转换为字符串。
  2. 解析代码
    ESLint 使用 JavaScript 解析器(如 Espree)将代码解析成抽象语法树(AST)。AST 是一种结构化的表示形式,AST 是一个树状结构,表示代码的语法结构,它将代码按照语法结构分解成树状结构,便于分析和处理。

3. 应用规则检测

到了这一步,ESLint 已经有了配置和要检查的代码语法树。接下来就是规则检测的核心阶段:

  1. 规则注册
    ESLint 会根据配置文件和插件,注册所有需要应用的检测规则。每个规则都是一个独立的函数,用于检查代码中的特定问题。
module.exports = {
  create: function(context) {
    return {
      BinaryExpression(node) {
        if (node.operator === '===') {
          context.report({
            node,
            message: "Use '==' instead of '==='"
          });
        }
      }
    };
  }
};
  1. 遍历 AST
    有了 AST,ESLint 就开始应用规则了。每个规则都是一个函数,接受 AST 作为输入,遍历 AST 节点,检查是否违反了规则,发现代码中的潜在问题。例如,假设我们有一个规则要求使用双等号()而不是三等号(=),规则函数会检查所有的比较操作符,如果发现三等号,就会报告问题。
  2. 收集报告
    每当发现一个问题,规则函数会生成一个报告(包含问题的位置、描述和建议)。ESLint 会收集所有的报告,准备在最终阶段输出。

4. 输出结果

检查完成后,ESLint 需要将结果反馈给开发者。这个过程包括两部分:

  1. 格式化输出
    ESLint 会根据配置中的格式化选项(如 stylish 或 json 等)将问题报告格式化为易读的输出形式。
  2. 输出到终端或文件
    ESLint 会将格式化后的结果输出到终端,或者根据配置保存到指定的文件中。如果你使用了 --fix 选项,ESLint 还会自动修复一些可以修复的问题,并将修改后的代码重新写入文件。
/path/to/file.js
  1:10  warning  Use '==' instead of '==='  eqeqeq

实战案例

我们以 no-debugger 规则为例,具体说明 ESLint 从执行命令到最终处理代码的整个流程。no-debugger 规则禁止在代码中使用 debugger 语句,这有助于避免开发阶段的调试语句留在生产代码中。

1. 初始化阶段

  1. 加载配置文件
    假设你的 .eslintrc.json 配置文件如下:
{
    "rules": {
        "no-debugger": "error"
    }
}

ESLint 会读取这个配置文件,了解要应用的规则和其级别(在这个例子中,no-debugger 规则被设置为错误级别 error)。

  1. 解析命令行参数
    如果你执行了如下命令:
    eslint src/
    ESLint 会解析这个命令,确定要检查 src 目录下的所有文件。

  2. 查找插件和扩展
    如果有配置插件,ESLint 会加载这些插件,但在这个例子中我们只使用了内置规则,所以这一步可以忽略。

2. 文件读取与解析

  1. 读取文件内容
    ESLint 会遍历 src 目录,读取所有 JavaScript 文件的内容。假设其中一个文件 example.js 的内容如下:
function foo() {
    debugger;
}
  1. 解析代码
    ESLint 使用 Espree 解析器将 example.js 的内容解析为 AST。对于上面的代码片段,生成的 AST 可能部分如下:
{
    "type": "Program",
    "body": [
        {
            "type": "FunctionDeclaration",
            "id": {
                "type": "Identifier",
                "name": "foo"
            },
            "body": {
                "type": "BlockStatement",
                "body": [
                    {
                        "type": "DebuggerStatement"
                    }
                ]
            }
        }
    ]
}

3. 应用规则检测

  1. 规则注册
    ESLint 会根据配置文件注册 no-debugger 规则。no-debugger 规则的实现大致如下:
module.exports = {
    meta: {
        type: 'suggestion',
        docs: {
            description: 'disallow the use of `debugger`',
            category: 'Possible Errors',
            recommended: true
        },
        schema: []
    },
    create(context) {
        return {
            DebuggerStatement(node) {
                context.report({
                    node,
                    message: 'Unexpected `debugger` statement.'
                });
            }
        };
    }
};
  1. 遍历 AST
    ESLint 会遍历 example.js 的 AST。当遍历到 DebuggerStatement 节点时,触发 no-debugger 规则的检查函数:
DebuggerStatement(node) {
    context.report({
        node,
        message: 'Unexpected `debugger` statement.'
    });
}

这个函数会生成一个问题报告,指出在代码中发现了 debugger 语句。

3. 收集报告:

ESLint 收集上述报告,记录下问题出现在 example.js 的具体位置,并记录问题描述。

4. 输出结果

  1. 格式化输出
    ESLint 会根据默认的输出格式(如 stylish)将报告格式化。格式化后的输出可能如下:
 /path/to/src/example.js       
 2:3  error  Unexpected `debugger` statement  no-debugger   
  1. 输出到终端或文件
    最终,ESLint 会将格式化后的结果输出到终端,帮助开发者发现并修复代码中的问题。

总结

通过以上步骤,ESLint 能够帮助开发者保持代码一致性,提高代码质量。它的内部工作原理虽然复杂,但通过解析配置、读取文件、解析代码、应用规则和报告问题这几个主要步骤,我们可以更好地理解和应用 ESLint。

;