ESLint那些事

本文深入探讨ESLint的原理、用途及自定义规则方法,讲解如何使用ESLint规范代码风格,减少错误,提升代码质量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

两年多以前,我刚刚学前端没多久。老师教我们使用可eslint。当我把eslint安装上的时候,满屏的错误一度让人崩溃,我当时心里想,这么难用的鬼东西,怎么会有人用呢?

时至今日,身边还有些朋友,对eslint望而生畏。

今天这篇文章,主要聊聊什么是Eslint,为什么要用它。它的实现原理是什么。工作中如何使用的Eslint,以及如何自定义Eslint规则。

本文整理自以下文章:

What & Why

为什么要使用Eslint?

JS是一个动态的弱类型语言,在代码编写的过程中,经常会出错,而因为其没有编译程序,为了寻找代码错误的地方,需要在执行的过程中不断的调试。

ESlint的作用就是让你在开发过程中发现自己的代码问题以及不规范的地方,提前发现问题所在,并且可以规范团队的代码风格保持一致。

什么是Eslint?

ESlint是一个开源的Js代码检查工具,它的目标是提供一个插件化的javascript代码检测工具。

ESLint 的核心可能就是其中包含的各种规则,这些规则大多为众多开发者经验的结晶:

总的来说,ESlint是一套每一个人都应该了解的并且遵循的JS代码规范。它可以让我们的代码风格一致、更加健壮、减少错误并用上社区的最佳实践。

原理

在许多方面,它和 JSLint、JSHint 相似,除了少数的例外:

  • ESLint 使用 Espree 解析 JavaScript。
  • ESLint 使用 AST 去分析代码中的模式
  • ESLint 是完全插件化的。每一个规则都是一个插件并且你可以在运行时添加更多的规则。

AST是Abstract Syntax Tree(抽象语法树)的缩写。

AST

也就是说,eslint使用Espress把js语法转换成AST。然后通过 AST selectors 找到静态代码中的内容,再根据rule的规则去判断这一段js是否符合eslint的规范。

安装和初始化ESlint

新建一个空的文件夹,执行以下的命令:

1、 npm init -y

2、 npm install eslint -D

2、 npx eslint --init

image-20200112155041929

完成以上的步骤,我们将会得到以下的文件夹:

image-20200112155112994

rule是如何工作的?

ESLint 的核心就是规则(rule),每条规则都是独立的,且都可以被设置为禁止off🈲️,警告warn⚠️,或者报错error❌。

我们选择"no-debugger": "error" 来看看 rule 是如何工作的。源码如下

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

        docs: {
            description: "disallow the use of `debugger`",
            category: "Possible Errors",
            recommended: true,
            url: "https://eslint.org/docs/rules/no-debugger"
        },

        fixable: null,
        schema: [],

        messages: {
            unexpected: "Unexpected 'debugger' statement."
        }
    },

    create(context) {

        return {
            DebuggerStatement(node) {
                context.report({
                    node,
                    messageId: "unexpected"
                });
            }
        };
    }
};

一条 rule 就是一个 node 模块,其主要由 metacreate 两部分组成,其中

  • meta 代表了这条规则的元数据,如其类别,文档,可接收的参数的 schema 等等。
  • create:如果说 meta 表达了我们想做什么,那么 create 则用表达了这条 rule 具体会怎么分析代码;

Create 返回的是一个对象,其中最常见的键的名字可以是上面我们提到的选择器,在该选择器中,我们可以获取对应选中的内容,随后我们可以针对选中的内容作一定的判断,看是否满足我们的规则,如果不满足,可用 context.report()抛出问题,ESLint 会利用我们的配置对抛出的内容做不同的展示。

上面的代码实际上表明在匹配到 debugger 语句时,会抛出 "Unexpected 'debugger' statement." 。

AST

关于更多的Rules规则,可以查看「eslint工作原理探讨」

plugin

plugin 有两重概念:

  1. 一是 ESLint 配置项中的字段,如 plugins: ['react',],;
  2. 二是社区封装的 ESLint plugin,在 npm 上搜索eslint-plugin-就能发现很多,比较出名的有 eslint-plugin-reacteslint-plugin-import

plugin 其实可以看作是第三方规则的集合,ESLint 本身规则只会去支持标准的 ECMAScript 语法,但是如果我们想在 React 中也使用 ESLint 则需要自己去定义一些规则,这就有了 eslint-plugin-react

我们在日常的工作中,也可以自定义符合自己团队风格的plugin提供给其他的队友使用。

工作中是如何使用的?

通常我们再日程的工作中,不会使用npx eslint执行代码检查,而是在IDE中自动提醒Eslint的错误。

在Vscode中,需要安装Eslint插件。

image-20200112161825873

如果使用该插件,需要在项目中或者全局安装eslint.否则,eslint插件会报错。

image-20200112162052045

当然,如果你用的webstorm,就不用这么麻烦安装插件啦。

VsCode中可以使用自动保存autoSave, ctrl P,使用保存时自动格式化eslint

image-20200112163411079

这里有一份「大前端」课程中提供的简单settings配置,可以供小伙伴们添加到settings.json中使用:

...
  "eslint.validate": [
    "javascriptreact",
    "typescriptreact",
    {
      "language": "html",
      "autoFix": true
    },
    {
      "language": "vue",
      "autoFix": true
    },
    {
      "language": "javascript",
      "autoFix": true
    },
    {
      "language": "typescript",
      "autoFix": true
    }
  ],
...
  "editor.codeActionsOnSave": {
    "source.fixAll.tslint": true,
    "source.fixAll.eslint": true
  },
  // prettier
  "prettier.trailingComma": "es5",
  // vetur
  "vetur.format.defaultFormatter.js": "none",
  "vetur.validation.template": false,
  // default use eslint, NO NEED re-config for twice
  // "vetur.format.defaultFormatterOptions": {
  //   "prettier": {
  //     "semi": false,
  //     "singleQuote": true,
  //     "eslintIntegration": true,
  //     "trailingComma": "all"
  //   }
  // },
  // Files exclude from tree

自定义的ESLint规则

只需要满足 ESLint 的规定,ESLint 支持自定义 parser,实际上社区在这方面也做了很多工作。比如

自定义的 parser 使用方法如下:

{
    "parser": "./path/to/awesome-custom-parser.js"
}

通过自定义 parser ,ESLint 的使用场景又被大大拓展。

自定义eslint的流程是这样的:

image-20200112170747058

下面,我们结合一个小例子,看看自定义的规则是如何实现的:

插件目标:禁止项目中setTimeout的第二个参数是数字。

实现步骤

1、安装NPM包

ESLint官方为了方便开发者开发插件,提供了使用Yeoman模板(generator-eslint)。

对于Yeoman我们只需知道它是一个脚手架工具,用于生成包含指定框架结构的工程化目录结构。

npm install -g yo generator-eslint

创建一个文件夹:

mkdir eslint-plugin-demo
cd eslint-plugin-demo

命令行初始化ESLint插件的项目结构:

yo eslint:plugin

下面进入命令行交互流程,流程结束后生成ESLint插件项目框架和文件。

? What is your name? OBKoro1
? What is the plugin ID? korolint   // 这个插件的ID是什么
? Type a short description of this plugin: XX公司的定制ESLint rule // 输入这个插件的描述
? Does this plugin contain custom ESLint rules? Yes // 这个插件包含自定义ESLint规则吗?
? Does this plugin contain one or more processors? No // 这个插件包含一个或多个处理器吗
// 处理器用于处理js以外的文件 比如.vue文件
   create package.json
   create lib/index.js
   create README.md

现在可以看到在文件夹内生成了一些文件夹和文件,但我们还需要创建规则具体细节的文件。

2、创建规则

上一个命令行生成的是ESLint插件的项目模板,这个命令行是生成ESLint插件具体规则的文件。

yo eslint:rule // 生成 eslint rule的模板文件

创建规则命令行交互:

? What is your name? OBKoro1
? Where will this rule be published? (Use arrow keys) // 这个规则将在哪里发布?
❯ ESLint Core  // 官方核心规则 (目前有200多个规则)
  ESLint Plugin  // 选择ESLint插件
? What is the rule ID? settimeout-no-number  // 规则的ID
? Type a short description of this rule: setTimeout 第二个参数禁止是数字  // 输入该规则的描述
? Type a short example of the code that will fail:  占位  // 输入一个失败例子的代码
   create docs/rules/settimeout-no-number.md
   create lib/rules/settimeout-no-number.js
   create tests/lib/rules/settimeout-no-number.js

加了具体规则文件的项目结构

.
├── README.md
├── docs // 使用文档
│   └── rules // 所有规则的文档
│       └── settimeout-no-number.md // 具体规则文档
├── lib // eslint 规则开发
│   ├── index.js 引入 导出rules文件夹的规则
│   └── rules // 此目录下可以构建多个规则
│       └── settimeout-no-number.js // 规则细节
├── package.json
└── tests // 单元测试
    └── lib
        └── rules
            └── settimeout-no-number.js // 测试该规则的文件

3、安装项目依赖

npm install

rule完整文件

lib/rules/settimeout-no-number.js:

module.exports = {
    meta: {
        docs: {
            description: "setTimeout 第二个参数禁止是数字",
        },
        fixable: null,  // 修复函数
    },
    // rule 核心
    create: function (context) {
        // 公共变量和函数应该在此定义
        return {
            // 返回事件钩子
            'CallExpression': (node) => {
                if (node.callee.name !== 'setTimeout') return // 不是定时器即过滤
                const timeNode = node.arguments && node.arguments[1] // 获取第二个参数
                if (!timeNode) return // 没有第二个参数
                // 检测报错第二个参数是数字 报错
                if (timeNode.type === 'Literal' && typeof timeNode.value === 'number') {
                    context.report({
                        node,
                        message: 'setTimeout第二个参数禁止是数字'
                    })
                }
            }
        };
    }
};

context.report():这个方法是用来通知ESLint这段代码是警告或错误的,用法如上。在这里查看contextcontext.report()的文档。

规则写完了,原理就是依据AST解析的结果,做针对性的检测,过滤出我们要选中的代码,然后对代码的值进行逻辑判断

4、发布插件

eslint插件都是以npm包的形式来引用的,所以需要把插件发布一下:

  1. 注册:如果你还未注册npm账号的话,需要去注册一下。
  2. 登录npm: npm login
  3. 发布npm包: npm publish即可,ESLint已经把package.json弄好了。

5、集成到项目:

安装npm包:npm i eslint-plugin-korolint -D

常规的方法: 引入插件一条条写入规则

// .eslintrc.js
module.exports = {
  plugins: [ 'korolint' ],
  rules: { 
    "korolint/settimeout-no-number": "error"
 }
}

extends继承插件配置:

当规则比较多的时候,用户一条条去写,未免也太麻烦了,所以ESLint可以继承插件的配置

修改一下lib/rules/index.js文件:

'use strict';
var requireIndex = require('requireindex');
const output = {
  rules: requireIndex(__dirname   '/rules'), // 导出所有规则
  configs: {
    // 导出自定义规则 在项目中直接引用
    koroRule: {
      plugins: ['korolint'], // 引入插件
      rules: {
        // 开启规则
        'korolint/settimeout-no-number': 'error'
      }
    }
  }
};
module.exports = output;

使用方法:

使用extends来继承插件的配置,extends不止这种继承方式,即使你传入一个npm包,一个文件的相对路径地址,eslint也能继承其中的配置。

// .eslintrc.js
module.exports = {
  extends: [ 'plugin:korolint/koroRule' ] // 继承插件导出的配置
}

总结

ESLint 可谓是现代前端开发过程中必备的工具了。ESLint 做为必备工具之一,能减少团队协作的问题,个人代码风格问题,减少Bug的错误,是非常值得我们深入了解学习的。

这篇文章,我在咖啡厅花了整整一下午整理学习,收获颇丰。感谢掘金作者@OBKoro1,@zhangwang的分享。

更多参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值