HTMLHint无法支持真正的AST规则,因其仅提供token流而非节点对象,缺乏parentNode、children等DOM遍历能力;真正需跨节点语义检查时应选用parse5手写AST遍历逻辑。

HTMLHint 做不了语法树级规则,别在它上面浪费时间写 AST 遍历逻辑——它根本没给你 parentNode 或 children。
为什么 HTMLHint 无法支持真正的 AST 规则
HTMLHint 的规则函数接收的是 token 流或单行文本,不是节点对象。你拿不到 node.tagName、node.isSelfClosing,更没法向上查 node.parentNode。所谓“AST 支持”是常见误解,混淆了它和基于 parse5 或 htmlparser2 的工具链。
典型失效场景包括:
-
<template><img></template>中的img是否该有alt—— HTMLHint 只看到孤立的<img>标签,不知道它在template内 - 自定义组件(如
<my-card>)内部是否漏了role—— 它不解析组件边界,无法建立上下文语义 -
section下第一个子元素是否为h2—— 没有父子关系访问能力,纯靠正则匹配必然误判
用 parse5 手写 AST 规则的最小可行路径
如果你真需要跨节点语义判断,parse5 是目前最轻量、最可控的选择。它生成标准 W3C 兼容 AST,支持完整 DOM-like 遍历。
立即学习“前端免费学习笔记(深入)”;
实操建议:
- 安装:
npm install parse5 - 解析后手动 DFS:对每个
node判断node.nodeName === 'img',再用node.parentNode?.nodeName === 'FIGURE'检查父容器 - 注意
parse5.parse()返回的是Document节点,不是Element;需从document.childNodes开始遍历,跳过DocumentType节点 - 不要依赖现成 rule runner —— 每条规则都得自己写
traverse+condition,没有“插件化”捷径
示例片段(检查所有 img 是否在 figure 内且带 figcaption):
const { parse } = require('parse5');
const document = parse(html);
function traverse(node) {
if (node.nodeName === 'img') {
const parent = node.parentNode;
if (parent?.nodeName !== 'FIGURE') return false;
if (!Array.from(parent.childNodes).some(n => n.nodeName === 'FIGCAPTION')) return false;
}
if (node.childNodes) node.childNodes.forEach(traverse);
}
traverse(document);
把 HTML 当 JSX/Vue SFC 处理的适用边界
这条路只适合已工程化的项目,且必须接受额外编译步骤和模板约束。
适用前提:
- 项目已用 Webpack/Vite 解析
.vue或.jsx文件 - HTML 片段全部来自
<template>或return () => <div>...,而非拼接字符串 - 能容忍 ESLint 插件对非标准属性(如
v-if、ng-if)的误报,并手动配置eslint-plugin-vue或eslint-plugin-react的 parser options
不适用场景:
- SSR 模板(Nunjucks/EJS)中混写的 HTML
-
innerHTML += '<div>...</div>'这类运行时拼接 - 第三方 CMS 输出的原始 HTML 字符串
AST 方案最容易被忽略的性能陷阱
深度遍历本身不慢,但两个细节会让 CI 构建卡住或内存爆掉:
- 没设深度限制:超深 DOM(比如嵌套 > 50 层)会导致
parse5.parse()内存占用陡增,建议加maxBufferSize选项或提前截断 - 没做缓存:同一份 HTML 在多个规则间重复解析 —— 应先
parse()一次,再把 AST 传给各规则函数 - 正则兜底失效:当 HTML 含非法字符(如未转义的
&)导致parse5报错时,必须 fallback 到简单正则(如/<[a-z][^>]*>[^<]*<[a-z][^>]*>/i)快速告警,否则构建直接中断
真正难的从来不是“怎么写规则”,而是让规则在真实项目里稳、快、不误伤——AST 不是银弹,只是把问题从“检测不准”换成了“控制成本”。



















