通过定制化语法树检测规则排查HTML代码质量潜在技术漏洞
htmlhint无法实现ast级嵌套语义检查,因其规则仅基于token流或单行文本,不提供parentnode、children等ast节点属性;真需校验如“img是否在figure内”等语义,必须改用parse5构建真实ast并手动遍历。

HTMLHint 不能做 AST 级规则,别白费劲写“嵌套语义”检查
HTMLHint 的规则函数接收的是 token 流或单行文本,不是 AST 节点对象。你没法调用 node.parentNode、node.children 或判断 node.isSelfClosing —— 这些属性根本不存在。所有所谓“组件内 img 必须带 alt”“template 下的 button 要有 aria-label”的需求,在 HTMLHint 里注定失败。
常见错误现象:
- 写了遍历逻辑却收不到子节点信息,
node.children 是 undefined
- 试图用
node.tagName === 'FIGURE' 判断父级,结果 node 根本没 tagName 字段
- 文档里看到“支持自定义规则”,误以为能复刻 ESLint 风格的上下文感知
它真正能干的只有两类事:
- 正则匹配局部模式:比如
alt-require 查 <img> 是否含 alt 属性(不关心它在不在 <figure></figure> 里)
- 状态机驱动的配对检查:比如
tag-pair 确保 <div> 和 <code>
出现顺序合法(不校验是否被
<p></p> 包裹)
真要查嵌套语义?得换 parse5 + 手动遍历
想检查 “所有 <img> 是否在 <figure></figure> 内且紧邻 <figcaption></figcaption>”,就得放弃 HTMLHint,用 parse5 构建真实 AST,再写 DFS 遍历逻辑。
实操建议:
- 安装:
npm install parse5
- 解析后拿到的是标准 DOM-like 树结构,
node.childNodes、node.parentNode 全都有
- 每条规则都要自己写完整遍历 + 条件判断,没有现成 rule runner
- 性能要注意:大文件(>1MB)下
parse5.parse() 可能卡顿,建议加 try/catch 并设超时
示例片段(只查 <img> 是否在 <figure></figure> 下):
html-deploy
使用 htmlcode.fun 将 HTML 内容或文件部署到网页,适用于用户要求“部署到网页”“托管此 HTML”“生成此前端...的实时链接”等场景。
下载
const parse5 = require('parse5');
const document = parse5.parse(html);
function findImgInFigure(node) {
if (node.nodeName === 'IMG' && node.parentNode?.nodeName === 'FIGURE') {
return true;
}
return node.childNodes?.some(child => findImgInFigure(child)) || false;
}
Vue/React 项目更省事:转成 JSX/SFC 再交给 ESLint
如果你的 HTML 实际是 Vue 单文件组件(.vue)或 React JSX(.tsx),别硬啃原生 HTML 解析 —— 把模板交给对应生态的 lint 工具更可靠。
适用场景:
-
eslint-plugin-vue 能识别 <mybutton></mybutton> 组件内是否漏了 role
-
eslint-plugin-react 可检查 <img> 在 <article></article> 下是否缺失 alt(依赖 JSX 层语义)
- 前提是你已配置好
@vue/compiler-sfc 或 @babel/preset-react,能把模板编译成 AST
注意陷阱:
- 纯 HTML 文件(
.html)无法直接喂给 ESLint,必须先转格式或走构建流程
- 第三方组件库的自定义标签(如
<ant-design-button></ant-design-button>)需额外配置 settings.react.extendedAPIs 才能识别
运行时 DOM 对比才是暴露真实问题的关键
静态分析永远看不到 JS 动态拼接的 HTML 错误。比如 CMS 后台保存后,前端用 innerHTML += '<div><p>text</p></div>',W3C 验证和 HTMLHint 全部通过,但浏览器实际渲染出错嵌套。
正确做法是在 DOMContentLoaded 触发瞬间,用 fetch(location.href, { cache: 'no-store' }) 拉原始 HTML,再用 new DOMParser().parseFromString() 解析对比 document.documentElement.outerHTML —— 这才能发现服务端漏渲染、CDN 缓存脏数据等问题。
容易被忽略的细节:
-
document.documentElement.outerHTML 返回的是浏览器“修复后”的 DOM,自动补闭合、拆非法嵌套,完全掩盖原始缺陷
- 若页面启用了 CSP
connect-src,fetch 可能被拦截,得 fallback 到从 <script type="application/json"></script> 提取可信片段作锚点
- 第三方 SDK 注入的
<div class="ad-banner"> 若没闭合,仅靠静态扫描永远扫不出来
</div>
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!