起因
之前需要 Vue 全局错误管理,但是每个人的代码风格都不一样,导致有些错误无法报告到全局,所以就去看了一下 eslint 相关的规则,发现没有可以直接用的,然后就自己写了一个插件,下面写一下 eslint 插件的简单开发流程。
自定义规则
假设在 vue 中我们想尽可能的用同步写法代替回调写法,从 $nextTick 开始
例如:
// vue 某个方法中
async xxx (){
this.$nextTick(() => {
// do something
})
}
我们想变成
// vue 某个方法中
async xxx (){
await this.$nextTick()
// do something
}
// 异步函数调用注意:
// 咱们调用 xxx 方法的时候,假设该方法是 async 函数,或者返回的是 promise
// 这个时候我们直接执行 xxx(),是无法捕获错误的,
// 需要 await xxx(),才可以捕获错误
开始
eslint 官方推荐使用 yeoman 配合 generator-eslint(eslint 官方开发的基于 yeoman 的生成器)生成一个 eslint 插件的开发模板,yeoman 后面有时间会单独讲下,是个好东西。
安装依赖
// 安装 yeoman
npm i -g yo
// 安装 eslint 插件模板生成器
npm i -g generator-eslint
初始化自己的 eslint 插件
eslint 插件的名字必须是这种格式:eslint-plugin-(插件名字)
// 先创建一个文件夹,然后进去
// 初始化 eslint 插件模板
yo eslint:plugin
初始化 eslint 规则
yo eslint:rule
项目结构
eslint 运行原理
简单来说,eslint 会把代码解析成 AST 语法树,然后我们通过 AST 去实现我们的自定义规则!
AST
简单来说 AST 就是描述代码的一个抽象语法树,代码或者框架可能有各种各样的写法,但是我们只要将其转换为 AST 语法树,就可以通过操作 AST 语法树去随意操控我们的代码。
简单的例子:
开发注意
下图是 eslint 规则输出的基本格式,这个 create 函数是精髓
书写 await-to-next-tick 规则
// 对照一下上面的 AST 语法树,下面就是一个简单的判断,我们的规则就 ok 了。
module.exports = {
...,
create: function(context) {
return {
'CallExpression' (node) {
if (
node?.arguments?.length && // 判断调用 $nextTick 是否传入回调
node?.callee?.object?.type === 'ThisExpression' &&
node?.callee?.property?.name === '$nextTick'
){
// 报告错误
ctx.report({
node,
message: '使用 await 调用该函数'
})
}
}
}
}
};
如何调试 eslint 规则
1.修改一波入口文件
/**
* @fileoverview 佐助的自定义规则
* @author 佐助
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
var requireIndex = require("requireindex");
//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------
module.exports = {
// 引入所有的规则
rules: requireIndex(__dirname + "/rules"),
configs: {
// 自定义配置
recommed: {
plugins: ['zz-rule'],
rules: {
'zz-rule/await-to-next-tick': 2
}
}
},
}
2.eslint 插件的根目录下
// eslint 插件的根目录下
npm link
3.在 vue2 工程中使用 eslint 插件
// Vue2 工程根目录下
npm link eslint-plugin-zz-rule
4.引入咱们的插件
// eslint config 文件中
extends: [
// 对应咱们上面的插件名称
"plugin:zz-rule/recommed"
],
注意
我以 vscode 举例(首先得安装 eslint 扩展程序),然后进入 vue2 工程,你点击这个就可以看到 eslint 插件到时候的输出
如果你更改了 eslint 的代码,记得重新打开 vue2 工程才会生效
规则效果
鼠标触摸上去就会有咱们的错误提示~!
如何自动修复我们的错误
1.看下 eslint 官方创建规则的文档
2.写一个修复函数
/**
* @fileoverview 使用 await 调用该函数
* @author 佐助
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "使用 await 调用该函数",
category: "Fill me in",
recommended: false
},
fixable: 'code', // 要修复的话就把这个改为 code
schema: [
// fill in your schema
]
},
create: function(ctx) {
return {
'CallExpression' (node) {
if (
node?.arguments?.length &&
node?.callee?.object?.type === 'ThisExpression' &&
node?.callee?.property?.name === '$nextTick'
) {
// 返回一个SourceCode对象,你可以使用该对象处理传递给 ESLint 的源代码。
const sourceCode = ctx.getSourceCode()
// node.arguments 就是我们 this.$nextTick(我是参数函数) 里面的参数
// .body 就是参数函数体
// .body.body 就是参数函数体里面的具体代码
let content = `\n${Array.from(node.arguments[0].body.body)
.map(item => sourceCode.getText(item))
.join('\n')}`
ctx.report({
node,
message: '使用 await 调用该函数',
fix(fixer) {
return [
// 给函数前面加个 await
fixer.insertTextBefore(node, 'await '),
// 删除 this.$nextTick(我是参数函数) 里面的参数
fixer.remove(node.arguments[0]),
// 把用户写的代码放到函数下面去
fixer.insertTextAfter(node , content)
]
}
})
}
}
}
}
};
3.效果
正式发布 npm
// eslint 插件根目录下
npm login
npm publish
// Vue2 工程中
npm i -D eslint-plugin-zz-rule