前端工程化(9):编写一个eslint插件来解决实际项目中的问题

首先请大家不要喷笔者在这个年代还在写关于如何编写 eslint 插件的文章,因为当你们知道我写的这个 eslint 插件还是跟 vue2 项目相关的时候,你发现你们喷早了。其实关于 eslint 的文章早在两三年前就规划在前端工程化的系列里了,如今写下这篇文章一是为了给自己一个交代,二是给大家分享下我这次开发 eslint 插件解决实际项目问题的心路历程。大家感兴趣的话可以继续往下看~

1. 实际项目中碰到的问题

熟悉 vue2 的人应该都知道,vue2 通过对定义在 data 选项中的数据进行响应式劫持,从而达到数据驱动视图更新的目的。而在实际开发中,很多开发者都会在 data 选项中滥定义变量,从而造成不必要的性能浪费。所以,我要写的这个规则的作用是:

检测无用的响应式变量

在日常需求迭代中对于一些不再使用的响应式变量没有及时删除:

检测有用但无需响应的变量

有些数据并不是用在模板中,也不需要监听它的变化,只是想在组件的上下文中共享这个数据:

像这种情况,推荐的写法是把这个数据挂载到组件实例 this 上,无需在 data 选项中定义消耗性能:

但不建议规则提供上述写法的自动修复功能,因为项目的变量依赖复杂,容易造成响应式丢失的问题,还是把这个修复行为交给用户手动操作!

虽然上述滥定义的响应式变量在大多数场景下都不会造成性能问题,但为了追求性能最强化、代码最优化,我想这个规则多多少少都会有一些帮助。

交代完背景,接下来就开始开发插件了。

2. 插件开发环境搭建

eslint 官方为了方便开发者开发插件,提供了 generator-eslint 脚手架工具,用于生成包含指定框架结构的工程化目录结构:

bash 复制代码
npm install -g yo generator-eslint

新建一个文件夹:

bash 复制代码
mkdir eslint-plugin-vue-extends
cd eslint-plugin-vue-extends

命令行初始化 eslint 插件的工程

bash 复制代码
yo eslint:plugin

? What is your name? eslint-plugin-vue-extends
? What is the plugin ID? eslint-plugin-vue-extends
? Type a short description of this plugin: This plugin is an extension of eslint-plugin-vue
? Does this plugin contain custom ESLint rules? Yes 
? Does this plugin contain one or more processors? No

命令行创建 eslint 规则模板

bash 复制代码
yo eslint:rule

? What is your name? no-unused-data
? Where will this rule be published? ESLint Plugin
? What is the rule ID? no-unused-data
? Type a short description of this rule: This rule reports data that have not been used in the template
? Type a short example of the code that will fail: 

执行完上述两个命令行的交互后,文件的项目结构就创建完毕。不过为了方便调试,我们还得改造下 tests 文件夹。eslint 脚手架默认提供了 mocha 自动化测试工具来辅助调试,但由于我们需要模拟 .vue 单文件环境,且各种模板语法较多,所以我们舍弃 mocha,直接创建一个 test.vue 文件来进行测试,最后的文件结构如下:

配置规则导出 lib/index.js 文件

配置的时候有两点要注意:

  1. eslint 要 parse vue 模板需要使用 vue-eslint-parser
  2. configs 的作用是可以暴露多个插件推荐的默认规则,方便使用。
bash 复制代码
npm link && npm link eslint-plugin-vue-extends

配置工程中的 .eslintrc.js 文件

需要配置两点:

  1. 由于工程中 link 了自身的软链接,extends 中可以直接引入 eslint 插件名,eslint 插件名根据自己配置的规则导出文件中的 configs 来设置;
  2. parser 同样要设置成 vue-eslint-parser,要不然 .vue 文件会报错。

package.json 中配置 test 命令

json 复制代码
"scripts": {
    "test": "eslint tests/test.vue"
},

至此开发环境就搭建结束了,接下来就开始开发具体的校验规则了。

3. 规则编写

规则的结构

插件的结构由两部分组成:

  1. meta:描述插件本身的元信息,重点关注两个属性 fixable(是否开启修复) 和 messages (报错提示语):
  1. create:规则实现的核心,它返回一个 visitor 对象,该对象具有 eslint 遍历代码的抽象语法树。但由于我们用了 vue-eslint-parser,所以得返回一个 vue-eslint-parser 提供的 visitor:

defineTemplateBodyVisitor 接受两个 visitor,一个是 template 的 visitor,一个是 script 的 visitor。所以规则实现的大体思路就是:先通过 templateVisitor 收集 template 中用到的变量,然后通过 scriptVisitor 遍历 data 选项中的变量,如果收集到的 template 中用到的变量不包括 data 选项中的变量,则该 data 变量 report 错误

template ast 分析

借助astexplorer分析 .vue 模板的 ast 树结构,可以发现 template 中每个表达式的节点都是 VExpressionContainer,我们可以选取这个表达式作为入口:

这个节点下又有多种类型的节点,比如属性表达式、逻辑表达式、条件表达式等等,目前收集到的子节点类型有:

对应的 ast 节点为:

Identifier
MemberExpression
ArrayExpression
UnaryExpression
CallExpression
BinaryExpression
ConditionalExpression
TemplateLiteral
VFilterSequenceExpression
LogicalExpression
ObjectExpression
VForExpression

然后针对上述子节点做分支判断并收集变量:

script ast 分析

为了保证能选到正确的 data,先选中 export default 节点,在使用子集选择器 > 查找到 data 函数 return 的 ObjectExpression 对象节点(选择方式可能还有优化空间,还请 ast 高手赐教):

分析完 template 和 script 的 ast 后,通过加打印,不停的执行 npm run test 来测试变量收集的准确性。完整代码在github上,大家有兴趣可以看看。

4. 总结

目前这个插件(确切来说是这个规则)已经在我们系统中应用起来了,并且也检测出了大量的滥定义变量,原本是以检测有用但无需响应的变量为出发点开发的这款插件,没想到却检测出了大量的无用的僵尸响应式变量。

但是,这个插件还存在一个不足的地方,无法检测间接依赖。 也就是说,这个变量虽然没有在 template 中使用,但是却被别的在 template 中使用的变量依赖了,这个功能要做起来,属实有点复杂(不知这是不是 vue 官方没有提供这个插件的原因)。不过不重要,这种复杂的场景还是靠人工比较靠谱,而我这个插件的定位就是帮助开发者先检测出一些显而易见的滥定义响应式变量。

最后,这个插件已发布到npm,插件地址eslint-plugin-vue-extends,欢迎各位使用,也欢迎各位提出意见~~

相关推荐
莹雨潇潇8 分钟前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr17 分钟前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho1 小时前
【TypeScript】知识点梳理(三)
前端·typescript
安冬的码畜日常2 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
小白学习日记3 小时前
【复习】HTML常用标签<table>
前端·html
丁总学Java3 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele3 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
懒羊羊大王呀4 小时前
CSS——属性值计算
前端·css
DOKE4 小时前
VSCode终端:提升命令行使用体验
前端