HTML代码质量优化:基于抽象语法树重组复杂DOM
AST重构HTML需保留语义标签、属性绑定与文本边界,避免破坏JS逻辑和CSS选择器。可安全删除的嵌套必须无布局样式且无事件绑定。重写后需验证选择器结果一致性及无障碍节点完整性。
直接使用AST重构HTML结构,并非简单地将代码转换为树再转换回来——本质上是让机器理解语义意图,然后按规则重写DOM树。盲目替换标签或删除嵌套,90%的情况下会破坏JS绑定、CSS选择器,甚至无障碍逻辑。下面具体说明操作方法。

AST解析HTML时必须保留的三类节点信息
HTML的AST(例如parse5或@html-eslint/parser生成的)与JS的AST不同,它必须显式保留三类信息:原生标签的语义、属性绑定的痕迹,以及文本节点的边界。否则后续重写时,关键上下文就会丢失。
class和id不能仅当作字符串处理——需要识别其是否被JS通过document.querySelector或事件委托引用(例如body.addEventListener('click', e => { if (e.target.classList.contains('btn')) ... }))。data-属性必须原样保留,同时检查其在Vue/React组件中是否被当作prop使用(例如)。- 文本节点中的换行和空格需标记为
preserveWhitespace: true,否则可能被误合并成Hello
World"HelloWorld"。
用AST找出真正可删的嵌套层
人工查看DOM嵌套时,容易将“看起来没用”的 AST重写HTML后,不能仅比对字符串是否一致——需要验证DOM行为是否等价。许多团队跳过此步骤,结果上线后发现表单提交失效、滚动锚点错位,或屏幕阅读器无法读出标题层级。 AST重构DOM的最大陷阱,并非解析不准确,而是将HTML视为纯模板处理——它实际上是运行时行为、样式系统、辅助技术、JS绑定的交汇点。任何脱离上下文的节点删除或标签替换,都可能在某个深夜的报警中突然爆发。:has()选择器依赖。
display、position、overflow这类布局相关样式,且父/子节点均无JS事件监听器绑定到该层级。Element节点,检查node.attributes中是否有style或class,再查询其CSSOM计算值(这需要配合Puppeteer或Chrome DevTools Protocol获取)。if (!hasLayoutStyle(node) && !hasJSBinding(node) && node.children.length === 1) → 可提升子节点。重写后必须验证的两个硬性条件
document.querySelectorAll('na v ul li a')返回的NodeList长度和顺序必须一致(即使结构变化,选择器的匹配结果不能改变)。tabindex、role、aria-的节点,重写后仍需出现在无障碍树中——可使用axe-core的await axe.run(document)自动检测。str.replace(/col-(d+)/g, 'grid-col-$1')),AST必须操作node.attributes对象,否则会破坏class="col-3 col-md-6 active"中的其他token。
