ESLint 深度解析:原理、规则与插件开发实践
在前端开发的复杂生态中,保障代码质量与规范性是构建稳健、可维护项目的基石。ESLint 作为一款强大的代码检查工具,其默认规则与插件能满足多数常见需求,但面对特定团队规范或项目独特要求,自定义 ESLint 插件便成为有力的扩展手段。本文将深入探讨如何打造自定义 ESLint 插件,并结合实际案例,详细阐述从创建到应用的全过程。
一、ESLint 基础回顾
ESLint 通过静态分析代码,将其转换为抽象语法树(AST),进而依据规则对代码进行细致检查。这一过程始于对代码的解析,默认使用 Espree 解析器,它将代码转化为树形结构,每个节点代表一种语法结构。例如,对于简单代码let num = 10;,在 AST 中会呈现为VariableDeclaration节点。
-
VariableDeclaration节点 :用于表示变量声明。它包含以下重要属性:
- declarations :是一个数组,存放变量声明符。在let num = 10;中,这个数组只有一个元素,即表示num变量的声明符。
- kind :表示声明的类型,如let、const或var。在上述例子中,kind的值为let。
ESLint 利用这些 AST 信息,对照规则库,找出代码中的潜在问题,如未使用的变量、错误的语法等。
二、自定义插件的需求场景
在团队协作项目中,统一的代码风格和规范至关重要。除了常规的代码格式与最佳实践,还可能存在一些特殊要求。例如,为了维护代码的文明性与专业性,我们要求代码中不得出现诸如 “sb250”“fuck” 等不文明、不专业的词汇。这类需求无法通过 ESLint 的默认规则实现,因此需要开发自定义插件来满足。
三、自定义 ESLint 插件开发流程
(一)工程搭建
-
初始化项目 :
- 首先确保全局安装了yo和generator - eslint。若未安装,可通过以下命令进行安装:
npm i -g yo
npm i -g generator-eslint
- 然后创建一个新目录用于插件项目,例如eslint - plugin - yinzhixiaxue,并进入该目录:
mkdir eslint-plugin-yinzhixiaxue
cd eslint-plugin-yinzhixiaxue
-
执行yo eslint:plugin命令,这是一个交互式命令,需要填写相关信息:
- 插件名称:例如eslint-plugin-yinzhixiaxue。
- 插件描述:描述插件的功能,如 “用于检查代码中是否存在不文明词汇的 ESLint 插件”。
- 是否包含自定义规则:选择Yes。
- 是否需要处理器:根据实际需求选择,通常对于简单的规则检查选择No。
-
安装依赖 :
- 插件开发依赖eslint和eslint-utils库,通过以下命令安装:
npm install eslint eslint-utils --save - dev
(二)创建规则
-
生成规则文件 :
-
在项目目录下执行npx yo eslint:rule命令,同样是交互式操作:
- 规则名称:例如no-offensive-words。
- 规则描述:如 “禁止在代码中使用不文明词汇”。
- 不通过的案例代码:可输入包含不文明词汇的代码示例,如let message = “fuck you”;。
-
完成后,项目目录结构中会生成lib/rules/no-offensive-words.js文件,该文件用于编写具体的规则逻辑。
-
(三)规则配置与编写
- 规则配置(meta对象) :
在lib/rules/no-offensive-words.js文件中,首先定义meta对象,用于描述规则的元信息:\
module.exports = {meta: {type: 'problem', // 表示该规则识别的代码可能会导致问题,需要优先解决,取值还可以是'suggestion'(建议优化代码)或'layout'(关注代码布局,如空格、分号等)docs: {description: '禁止在代码中使用不文明词汇', // 规则的详细描述category: 'Custom Rules', // 规则的分类,便于在规则列表中进行归类展示recommended: true, // 表示该规则是否推荐使用,若为true,在继承相关配置时可能会默认启用该规则url: null // 规则文档的链接,可指向详细介绍该规则的页面,这里暂设为null},messages: {noOffensiveWords: '代码中不允许使用不文明词汇' // 定义规则触发时的错误提示信息,这里的'noOffensiveWords'是一个自定义的标识符,可在后续代码中引用},fixable: null, // 表示该规则是否支持自动修复,null表示不支持,'code'表示可修复代码问题,'whitespace'表示可修复空格相关问题schema: [] // 用于定义规则的配置选项,这里为空表示该规则没有额外的配置参数},// 规则具体实现将在create函数中编写
};
- AST结构分析与规则编写(create函数) :
ESLint 通过遍历 AST 来应用规则,因此需要了解代码对应的 AST 结构。对于代码let message = “fuck you”;,在 AST Explorer(https://astexplorer.net/)中解析后,VariableDeclaration节点包含message变量的声明信息,而变量的初始值"fuck you"则存储在init属性指向的Literal节点中。
我们使用Literal节点是因为在这个规则中,我们关注的是字符串字面量中是否包含不文明词汇。Literal节点专门用于表示各种字面量,如字符串、数字、布尔值等。在检查不文明词汇时,我们只需要关心字符串类型的字面量,所以使用Literal节点来获取并检查变量值。
基于此,编写create函数来实现规则:\
module.exports = {meta: {// 省略meta部分已有的内容},create: function (context) {const offensiveWords = ['sb250', 'fuck'];return {Literal(node) {if (typeof node.value ==='string') {offensiveWords.forEach((word) => {if (node.value.includes(word)) {context.report({node,messageId: 'noOffensiveWords'});}});}}};}
};
在上述代码中:
- 定义了一个包含不文明词汇的数组offensiveWords。
- 在create函数返回的对象中,使用Literal节点访问方法。当 ESLint 遍历 AST 遇到Literal节点(通常用于表示字符串、数字等字面量)时,若其值为字符串类型,则检查该字符串是否包含offensiveWords中的词汇。若包含,则使用context.report方法报告错误,错误信息使用meta.messages中定义的noOffensiveWords。
(四)配置规则组
在lib/rules/index.js文件中,将新创建的规则集成到插件中:
const requireIndex = require('requireindex');
const rules = requireIndex(__dirname + '/rules');
module.exports = {rules,configs: {recommended: {plugins: ['yinzhixiaxue'],rules: {'yinzhixiaxue/no-offensive-words': 'error'}}}
};
这里通过requireIndex引入自定义规则,在configs中定义了recommended配置组,将no-offensive-words规则设置为error级别,即一旦违反该规则,ESLint 将抛出错误。
(五)补充测试用例
在tests/lib/rules/no-offensive-words.js文件中编写测试用例,以验证规则的正确性:
const rule = require('../../../lib/rules/no-offensive-words');
const RuleTester = require('eslint').RuleTester;const ruleTester = new RuleTester();
ruleTester.run('no-offensive-words', rule, {valid: ['let message = "Hello world";','const num = 10;'],invalid: [{code: 'let message = "sb250 is not allowed";',errors: [{ messageId: 'noOffensiveWords' }]},{code: 'const greeting = "fuck this";',errors: [{ messageId: 'noOffensiveWords' }]}]
});
测试用例分为valid和invalid两组:
- valid组包含符合规则的代码示例,这些代码应通过规则检查。
- invalid组包含违反规则的代码示例,每个示例都指定了预期的错误信息messageId,用于验证规则是否按预期触发错误。
四、自定义插件的使用
(一)插件安装
- 本地调试 :
在插件项目目录下执行npm link,然后在需要使用该插件的项目目录下执行npm link eslint-plugin-yinzhixiaxue。
- 发布安装 :
将插件发布到 npm 仓库后,在项目中通过npm install eslint-plugin-yinzhixiaxue --save - dev进行安装。
(二)项目配置
在项目的.eslintrc文件中,添加插件配置:
{"extends": ["plugin:yinzhixiaxue/recommended"],"parserOptions": {"ecmaVersion": 6,"sourceType": "module"}
}
这里通过extends继承了eslint-plugin-yinzhixiaxue插件的recommended配置组,同时根据项目需求配置了parserOptions,例如支持 ES6 语法和模块语法。
(三)关于 extends 和 plugins 的深入理解
在 ESLint 的配置体系中,extends和plugins扮演着不同但又紧密关联的角色。
extends主要用于继承已有的配置集合 ,它可以是一个配置文件的路径、可共享配置的名称,或是plugin:插件名/配置组名的形式。以"extends": [“plugin:react/recommended”]为例,它会一次性启用react插件中recommended配置组里预先定义好的多个规则 ,这些规则涵盖了插件作者认为在大多数情况下适合项目使用的代码检查规范,比如react/jsx-uses-react、react/jsx-uses-vars等规则会同时生效,无需开发者逐个配置。这大大简化了配置流程,确保项目遵循特定插件推荐的整体规则集。
plugins则是用于引入第三方插件 ,扩展 ESLint 的功能边界。在使用插件前,需要先通过npm安装插件,然后在.eslintrc文件的plugins数组中添加插件名,如"plugins": [“eslint-plugin-demo”] 。引入插件后,若想启用插件中的规则,有两种常见方式。一是在rules中单独配置,例如想启用eslint-plugin-demo插件中的rule1规则,可以设置"eslint-plugin-demo/rule1": “error” ,这种方式适用于对插件规则有精细化控制,只启用部分规则的场景;二是结合extends,通过继承插件提供的配置组来批量启用规则,就像前面提到的"extends": [“plugin:react/recommended”] 。
extends会默认开启当前的所有,plugin需要自己手动开启
extends侧重于对已有配置的复用,让开发者能够快速应用一套成熟的规则体系;而plugins更专注于引入新的功能,无论是自定义规则还是特殊文件处理器。在实际项目中,二者通常相互配合,开发者可以根据项目的具体需求,先用plugins引入插件,再巧妙运用extends来启用插件中合适的配置组,从而精准定制出符合项目特点的代码检查方案。
通过以上步骤,我们成功创建并应用了一个自定义 ESLint 插件,能够有效检查代码中是否存在不文明词汇,进一步提升了代码的规范性与专业性,为团队协作和项目维护提供了有力保障。在实际开发中,可根据更多具体需求,灵活扩展和调整自定义插件的规则,以满足不断变化的项目要求。
技术交流沟通➕V:yinzhixiaxue
相关文章:

ESLint 深度解析:原理、规则与插件开发实践
在前端开发的复杂生态中,保障代码质量与规范性是构建稳健、可维护项目的基石。ESLint 作为一款强大的代码检查工具,其默认规则与插件能满足多数常见需求,但面对特定团队规范或项目独特要求,自定义 ESLint 插件便成为有力的扩展手段…...

洛谷P1091
题目如下 思路 谢谢观看...

随机树算法 自动驾驶汽车的路径规划 静态障碍物(Matlab)
随着自动驾驶技术的蓬勃发展,安全、高效的路径规划成为核心挑战之一。快速探索随机树(RRT)算法作为一种强大的路径搜索策略,为自动驾驶汽车在复杂环境下绕过静态障碍物规划合理路径提供了有效解决方案。 RRT 算法基于随机采样思想…...

江科大51单片机笔记【9】DS1302时钟可调时钟(下)
在写代码前,记得把上一节的跳线帽给插回去,不然LCD无法显示 一.DS1302时钟 1.编写DS1302.c文件 (1)重新对端口定义名字 sbit DS1302_SCLKP3^6; sbit DS1302_IOP3^4; sbit DS1302_CEP3^5;(2)初始化 因为…...

ssm_mysql_暖心家装平台
收藏关注不迷路!! 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,还有大家在毕设选题(免费咨询指导选题),项目以及论文编写等相关问题都可以给我留言咨询,希望帮助更多…...

一周学会Flask3 Python Web开发-SQLAlchemy简介及安装
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili SQLAlchemy是Python编程语言下的一款开源软件。提供了SQL工具包及对象关系映射(ORM)工具,…...

< 自用文儿 > DELETED 设置速读 in Ubuntu24
systemctl 和 DELETED: 配置文件: vi /etc/systemd/system/ DELETED.service [Unit] DescriptionV2Ray Service Documentation DELETED Afternetwork.target nss-lookup.target[Service] #Usernobody CapabilityBoundingSetCAP_NET_ADMIN CAP_NET_BIN…...

自动化同步多服务器数据库表结构
当项目每次进行版本升级的时候,如果在这次迭代中涉及表结构变更,需要将不同的生产环境下,都需要同步表结构的DDL语句,比较麻烦,而且还有可能忘记同步脚本,导致生产环境报错.... 该方案采用SpringBootMybat…...

深入理解 HTML 元素:构建网页的基础
在网页开发的领域中,HTML(超文本标记语言)犹如一座大厦的基石,支撑起整个网页的结构与内容呈现。而 HTML 元素,则是构成这座基石的基本单位。今天,就让我们一同深入探索 HTML 元素的奥秘。 HTML 元素的构成…...

黄昏时间户外街拍人像Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色介绍 黄昏时分有着独特而迷人的光线,使此时拍摄的人像自带一种浪漫、朦胧的氛围 。通过 Lr 调色,可以进一步强化这种特质并根据不同的风格需求进行创作。Lr(Lightroom)作为专业的图像后期处理软件,提供了丰富的调色…...

OCPP扩展机制与自定义功能开发:协议灵活性设计与实践 - 慧知开源充电桩平台
OCPP扩展机制与自定义功能开发:协议灵活性设计与实践 引言 OCPP作为开放协议,其核心价值在于平衡标准化与可扩展性。面对不同充电桩厂商的硬件差异、区域能源政策及定制化业务需求,OCPP通过**扩展点(Extension Points)…...

哈希查找与深度优先遍历深度解析
一、算法基础概念对比 1.1 哈希查找的本质特征 哈希查找是一种基于哈希函数直接访问数据结构的查找技术,其核心在于通过数学映射建立键值与存储位置的直接关联。理想情况下时间复杂度可达O(1),实际应用中通过冲突处理机制实现近似常数时间的查找效率。…...

【powerjob】 powerjobserver注册服务IP错误
1、问题:powerjobserver 4.3.6 的服务器上有多个网卡对应多个ip,示例 eth0 :IP1 ,docker0:IP2 和worker 进行通信时 正确的应该时IP1 但是注册显示获取的确实IP2,导致 worker 通过ip2和server通信,网络不通,注册不上 2、解决方案 …...

Flutter底层实现
1. Dart 语言 Dart 是 Flutter 的主要编程语言。Dart 设计之初就是为了与 JavaScript 兼容,并且可以编译为机器代码运行。Dart 提供了一些特性,如异步支持(通过 async 和 await),这使得编写高效的网络请求和复杂动画变…...

亚信安全发布2024威胁年报和2025威胁预测
在当今数字化时代,网络空间已成为全球经济、社会和国家安全的核心基础设施。随着信息技术的飞速发展,网络连接了全球数十亿用户,推动了数字经济的蓬勃发展,同时也带来了前所未有的安全挑战。2024年,网络安全形势愈发复…...

【YOLOv12改进trick】StarBlock引入YOLOv12,创新涨点优化,含创新点Python代码,方便发论文
🍋改进模块🍋:StarBlock 🍋解决问题🍋:采用StarBlock将输入数据映射到一个极高维的非线性特征空间,生成丰富的特征表示,使得模型在处理复杂数据时更加有效。 🍋改进优势🍋:简单粗暴的星型乘法涨点却很明显 🍋适用场景🍋:目标检测、语义分割、自然语言处理…...

Android MVI架构模式详解
MVI概念 MVI(Model-View-Intent)是一种Android应用架构模式,旨在通过单向数据流和不可变性来简化应用的状态管理。MVI的核心思想是将用户操作、状态更新和界面渲染分离,确保应用的状态可预测且易于调试。 MVI的核心组件 Model&a…...

Spring AI Alibaba + Ollama:国产大模型DeepSeek LLM的低成本AI应用开发认知
写在前面 官方文档很详细,有开发需求可以直接看文档https://java2ai.com/docs/1.0.0-M5.1/get-started/博文内容为一个开发Demo,以及API简单认知理解不足小伙伴帮忙指正 😃,生活加油 我看远山,远山悲悯 持续分享技术干货…...

《2025软件测试工程师面试》功能测试篇
什么是功能测试? 功能测试是通过验证产品功能是否满足用户需求的过程,主要关注软件的功能是否符合需求规格说明,包括软件的各种功能、特性、性能、安全性和易用性等。 功能测试的流程包括哪些步骤? 需求分析:明确软件需求,确定测试范围。测试计划:制定详细的测试计划,…...

蓝桥杯2024年第十五届省赛真题-传送阵
题目描述 小蓝在环球旅行时来到了一座古代遗迹,里面并排放置了 n 个传送阵,进入第 i 个传送阵会被传送到第 ai 个传送阵前,并且可以随时选择退出或者继续进入当前传送阵。小蓝为了探寻传送阵中的宝物,需要选择一个传送阵进入&…...

非线性优化--NLopt算法(Android版本和Python示例)
通俗一点来说 非线性优化就是求函数的极值。我们想求一个 函数的极值问题的时候,线性函数是最简单的,因为是线性的嘛,单调增或者单调减,那么找到边界就可以求到极值。例如 f(x)=ax+b。 简单的非线性函数也是很容易求得极值的,例如f(x)=x*x.可以通过求导得到极值点,然后求…...

2025-03-06 ffmpeg提取SPS/PPS/SEI ( extradata )
一、需求 在某些情况下,可能需要直接使用H264/H265等原始数据流进行解码,比较常用的udp下的h264/h265。这时需要 av_parser_parse2 来组AVPacket,但对于视频的信息:宽高、格式等,可以根据 AVCodecParserContext 来获取࿰…...

海量数据融合互通丨TiDB 在安徽省住房公积金监管服务平台的应用实践
导读 安徽省住房公积金监管服务平台通过整合全省 17 家公积金中心的数据,致力于实现数据共享、规范化管理与高效数据分析。为了应对海量数据处理需求,安徽省选择 TiDB 作为底层数据库,利用其分布式架构和 HTAP 能力,实现了快速的…...

深入解析 supervision 库:功能、用法与应用案例
1. 引言 在计算机视觉任务中,数据的后处理和可视化是至关重要的环节,尤其是在目标检测、分割、跟踪等任务中。supervision 是一个专门为这些任务提供高效数据处理和可视化支持的 Python 库。本文将深入介绍 supervision 的功能、使用方法,并…...

【DeepSeek问答】访问QStandardItemModel::index(r,c)获取的空索引导致程序崩溃
好的,我现在来仔细思考一下用户的问题。用户在使用QStandardItemModel的setItem方法时,调用了setItem(4,6,item),也就是在第4行第6列的位置设置了一个item。然后他们尝试通过index(3,6)来获取这个位置的项目,想知道会有什么后果。…...

从开源大模型工具Ollama存在安全隐患思考企业级大模型应用如何严守安全红线
近日,国家网络安全通报中心通报大模型工具Ollama默认配置存在未授权访问与模型窃取等安全隐患,引发了广泛关注。Ollama作为一款开源的大模型管理工具,在为用户提供便捷的同时,却因缺乏有效的安全管控机制,存在数据泄露…...

Aws batch task 无法拉取ECR 镜像unable to pull secrets or registry auth 问题排查
AWS batch task使用了自定义镜像,在提作业后出现错误 具体错误是ResourceInitializationError: unable to pull secrets or registry auth: The task cannot pull registry auth from Amazon ECR: There is a connection issue between the task and Amazon ECR. C…...

通用信息抽取大模型PP-UIE开源发布,强化零样本学习与长文本抽取能力,全面适配多场景任务
背景与简介 信息抽取(information extraction)是指,从非结构化或半结构化数据(如自然语言文本)中自动识别、提取并组织出结构化信息。通常包含多个子任务,例如:命名实体识别(NER&am…...

基于uniapp的蓝牙打印功能(佳博打印机已测试)
相关步骤 1.蓝牙打印与低功耗打印的区别2.蓝牙打印流程2.1 搜索蓝牙2.2 连接蓝牙 3.连接蓝牙设备4.获取服务5.写入命令源码gbk.jsglobalindex.ts 1.蓝牙打印与低功耗打印的区别 低功耗蓝牙是一种无线、低功耗个人局域网,运行在 2.4 GHz ISM 频段 1、低功耗蓝牙能够…...

【Azure 架构师学习笔记】- Azure Databricks (15) --Delta Lake 和Data Lake
本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (14) – 搭建Medallion Architecture part 2 前言 ADB 除了UC 这个概念之外,前面【Azure 架构师学习笔记】- Azure Databricks (1…...