v4.0 — 复杂 HTML 还原度 99.6%(WeChat publish pipeline 硬化)
🎯 一句话总结
结构 100%、几何 99.6% 地把一篇 600 行带 grid / SVG / scroll-reveal / CTA 按钮的复杂动画 HTML 推到公众号草稿——在 MB 科技测试公众号端到端验证通过。
背景
v3.1 之前 publish 流水线只能稳定处理简单图文排版。遇到复杂外部 HTML(例如 落地页导出的产品页)会出现:
- 内容大段空白(scroll-reveal 默认 opacity:0 依赖 JS 显示)
- Hero 高度暴涨 2-3 倍(装饰性
position:absolute失效变 block) - 下载按钮消失(
<a>标签被微信后端 strip) - grid 布局退化成单列堆叠(旧逻辑没保留)
v4.0 对 publish 流水线做了四项"硬化"修复 + 一整套视觉一致性校准基础设施。
✨ 主要改动
Publish 流水线硬化(backend/app/api/v1/publish.py)
| 输入 | 新流水线处理 | 结果 |
|---|---|---|
opacity:0 |
→ opacity:1 |
修复 scroll-reveal 隐藏 |
transform:translate*(...) |
→ transform:none |
修复 slide-up 偏移 |
transition* / animation* |
strip | 避免 sub-pixel 漂移 |
position:absolute|fixed |
→ display:none |
微信删 position,失效的装饰直接隐藏 |
<a href="外部"> |
→ <section> 保留样式 |
微信删 a,视觉按钮留下 |
首个外部 <a href> |
自动抽 → content_source_url |
公众号"阅读原文"链接 |
视觉一致性基线 20.96% → 1.47%
在 H1-H6 + 段落基线 doc 上把 pixel diff 从 20.96% 校准到 1.47%:
_BODY_STYLE_FLUSH完整镜像微信.rich_media_content容器(letter-spacing:0.578px、padding:0 4px、display:flow-rootBFC、contenteditable启用line-break:after-white-space)- 标题/段落
line-height改用整数 px(h1=36..h6=21、p=29)取代 1.4 / 1.8 倍率,避免分数 line-box 的累积 round 分歧 - 渲染器把文本包在
<span leaf=""></span>镜像微信 ProseMirror ingest 行为
新增校准基础设施
backend/tests/visual/dump_wechat_computed_styles.py— dump WeChat 容器 computed style 到 JSON(校准 ground truth)scripts/test_publish_html.py—/publish/preview+/publish/draft+ 截图一条龙scripts/test_publish_direct.py— 绕过 API 直接 import,对付 uvicorn 旧字节码scripts/compare_source_vs_draft.py— source ↔ draft 四象限 side-by-side
📊 验证结果(printmaster_wechat_animated.html 600 行测试)
| 阶段 | Draft 高度 | vs source 4564 |
|---|---|---|
| v3.1(旧流水线) | 7496 px | +64.24% ❌ |
| v4.0 修复 reveal | 5212 px | +14.20% |
| v4.0 修复 absolute | 4519 px | -0.99% |
| v4.0 最终 | 4547 px | -0.37% ✅ |
结构还原度 100%(文字、图片、SVG、grid、flex、按钮文字全保留)。
📖 文档
- 踩坑全记录:
docs/research/RESEARCH_CORRECTIONS.md— 完整校准过程 + 2026-04-12 publish 陷阱 writeup - Agent 使用指南:
skill/mbeditor.skill.md新增 "Publish Pipeline 已知陷阱" 章节,六个陷阱 + 预防建议 - Changelog:
CHANGELOG.md[4.0.0]
🧪 部署验证
已本地 docker compose 验证:
docker compose build # ✅ 镜像构建成功
docker compose up -d # ✅ backend healthy
curl http://localhost:7072/api/v1/version
# {"version":"4.0.0","repo":"AAAAAnson/mbeditor"}全流水线 smoke test(grid=4、display:none=7、position:absolute=0、<a>=0、opacity:0=0、cta-btn 保留)全部 assertion 通过。
⚠️ 已知问题
- Host-port shadowing:如果有 stale Python 进程绑定相同端口(如 7072),docker 部署会被僵尸 listener shadow。排查:
Get-NetTCPConnection -LocalPort 7072 -State Listen看谁占着 - 本地开发 uvicorn:必须加
--reload否则改publish.py后不生效 - 1.47% 剩余 sub-pixel 差异:WeChat 容器 letter-spacing 0.578px 的字符漂移,无法消除(也不影响视觉)
- 外部链接:每篇文章最多一个外部可点击 URL(通过"阅读原文"),写多个
<a href>只有第一个有效
🙏 感谢
感谢 Claude Opus 4.6 (1M context) 全程陪同校准 + 六次 WeChat 草稿 push 迭代的耐心 debug。