ci/cd中运行html验证需嵌入vnu cli工具,配置--ascii-links和--no-lang-notice等参数确保精准判定,结合puppeteer渲染动态页、cheerio解析json输出生成github可跳转错误,并通过分支保护规则强制修复error后方可合并。

CI/CD 流程里怎么跑 HTML 验证
HTML 验证必须在代码提交后、部署前自动触发,不能靠人手动点。主流做法是用 nu-html-checker(vnu)作为 CLI 工具嵌入构建脚本,它不依赖浏览器,纯 Java 实现,稳定且支持标准错误码。
关键不是“能跑”,而是“跑得准”:
- 必须用
--ascii-links和--no-lang-notice关闭非关键提示,避免误判干扰 CI 状态 - 对动态生成页(如 Vue/React SSR 输出),需先用
puppeteer渲染再保存为静态 HTML 再验证,否则只验到骨架 - 若项目含大量第三方组件(如地图 SDK、广告 iframe),要加
--skip-non-html并配置白名单路径,防止因外部资源加载失败中断流程 - 错误阈值建议设为非零退出码(
exit 1)仅当出现Error级问题,Warning不阻断发布,但写入报告归档
怎么让验证结果真正驱动开发
验证工具输出一堆行号和错误描述没用,除非它能直接定位到源文件、关联 PR、甚至给出修复建议。工程上最有效的闭环是:
- 用
cheerio解析 vnu 的 JSON 输出,提取message、line、extract字段,转成 GitHub Actions 的::error file=xxx.html,line=12::Missing alt attribute格式,实现点击跳转 - 对常见模式(如缺失
alt、img标签未闭合)写简单修复脚本,配合prettier-plugin-html自动重写,而非只报错 - 把历史验证结果存进
SQLite,按日期+分支维度聚合统计错误类型分布,识别高频违规点(比如某次重构后aria-*误用激增) - 禁止将验证步骤放在
build脚本末尾——它应该和lint同级,在打包前就卡住,否则无效 HTML 已被打进 dist 目录
为什么本地验证通过,CI 却报错
典型现象是开发者本地 vnu index.html 显示 “Document checking completed. No errors or warnings.”,但 CI 报 Bad value “” for attribute “lang” 或 Element “main” not allowed as child of element “div”。根源往往不在 HTML 本身,而在环境差异:
-
vnuCLI 默认使用宽松的html5模式,但 CI 中若用了 Docker 镜像(如w3cvalidator/vnu),可能默认启用更严格的html5-all检查集 - 本地文件路径带中文或空格,
vnu在某些 shell 下解析失败,实际跳过验证;CI 使用标准化路径则暴露问题 - 前端构建产物中,
index.html可能被插件注入了额外标签(如webpack-plugin-html-inject插入的meta),而本地验证的是原始模板 - CI 运行时未设置
LANG=C.UTF-8,导致 vnu 对 Unicode 字符处理异常,误判属性值格式
别让验证变成摆设的三个硬约束
很多团队跑起来了 HTML 验证,但三个月后就形同虚设。真正卡住质量下限的,是下面这三条线:
- 所有
Error必须修复后才能合并进main分支,GitHub/GitLab 的 branch protection rule 要勾选 “Require status checks to pass before merging”,并绑定验证 job 名称 - 验证报告必须包含原始 HTML 片段(
extract字段)、出错位置(line/column)、规范依据链接(如指向 MDN 的<img>页面),不能只有模糊提示 - 每季度审计一次白名单规则——比如某个
iframe因第三方限制无法加title,当初加的--disable html-req-title是否还合理?有没有新方案替代?
最容易被忽略的是:验证工具本身不会理解业务语义。它说 button 缺少 type="submit" 是个 warning,但如果你的表单靠 JS 拦截 submit 并调用 API,这个 warning 其实是 false positive,必须用自定义规则显式忽略,而不是视而不见。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











