编写 ESLint 插件(上)

背景
最近在团队内落地统一规范时,需要保证“每个 SFC 模板至少包含一个 data-xxx 或 v-data-xxx”这类规范。研究了下,可选方案有三种:
- 文档宣导,依赖自觉
- Code Review 阶段全局扫描
- 在提交前通过自动化工具拦截
第三种方案接入成本低、反馈路径短,是目前工程化实践中的首选。实现手段通常有两种:编写构建插件(vite/webpack)或编写 ESLint 插件。后者配置统一、生态成熟,更利于长期维护,语义上也更符合 ESLint 场景。
实现思路
(ESLint 插件的完整规范可参考官方文档,本文仅聚焦关键步骤。)
ESLint 的核心流程可简化为三步:
- 解析器把源码生成 AST
- 插件基于 AST 做规则校验
- 若命中规则,则上报错误或警告
因此,开发插件的关键在于理解 AST 结构,并针对目标节点编写访问逻辑。
Vue 文件解析
在 Vue 工程里,构建侧常用 @vue/compiler-sfc。编写规则时,应改用 vue-eslint-parser,它专门处理 .vue 单文件,仅解析 <template> 区块并提供 template visitor,可直接在插件中使用。
规则实现示例
需求:模板中至少有一个 DOM 元素或自定义组件带 data-xxx 属性或 v-data-xxx 指令。
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Enforce at least one data-xxx or v-data-xxx attribute in template',
category: 'Best Practices',
recommended: true
},
fixable: null,
schema: []
},
create(context) {
return {
/*
* 只能匹配“指令”属性(v-data-xxx),若要同时检测普通 DOM 属性(如 data-xxx),需再写一条非指令属性选择器:
* 'VAttribute[directive=false][key.name^="data-"]'(node) { ... }
* 'VAttribute[directive=true][key.name.name^="data-"]'(node) {...}
* 改用 VElement 统一检查所有属性,无需区分指令与普通 DOM 属性
*/
VElement(node) {
const hasDataAttr = node.startTag.attributes.some(attr => {
const name = attr.directive ? attr.key.name.name : attr.key.name
return name.startsWith('data-')
})
if (!hasDataAttr) {
context.report({
node,
message: 'Template must contain at least one data-xxx or v-data-xxx attribute'
})
}
}
}
}
}
用例测试
ESLint 提供 RuleTester 工具,可在本地模拟完整校验流程:
const { RuleTester } = require('eslint')
const rule = require('./require-data-xxx-attributes')
const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser')
})
tester.run('require-data-xxx-attributes', rule, {
valid: [
{ code: '<div data-xxx></div>' },
{ code: '<div v-data-xxx></div>' },
{ code: '<custom data-xxx></custom>' }
],
invalid: [
{ code: '<div></div>', errors: [{ message: 'Template must contain at least one data-xxx or v-data-xxx attribute' }] },
{ code: '<custom></custom>', errors: [{ message: 'Template must contain at least one data-xxx or v-data-xxx attribute' }] }
]
})
发布与集成
插件开发完成后,发到 npm 即可。
另外,最好将 eslint 声明为 peerDependencies,毕竟eslint并不是插件的直接依赖。
后续
理解 ESLint 工作原理后,插件本身的编码并不复杂。但在真实业务落地时,仍需解决「仅对 .vue 生效」「组合多条规则」「提供统一配置入口」等细节。这些主题将在下篇展开。
- ← 上一篇
hello - 下一篇 →
超简单的主题切换技巧