
为什么要在 markdownToHtml 出口统一压掉标签间空白先说结论如果多个平台共用同一条 Markdown 转 HTML 渲染链最稳的修法通常不是在单个平台适配器里补丁而是把结构噪声在共享出口一次清干净。这次 OmniPost 修的就是一个很典型的共享层问题。问题最早在微信新版编辑器里暴露列表项之间的换行空白会被解释成空列表项结果 4 项列表能显示成 9 项奇数编号全空。但真正重要的不是“微信出 bug 了”而是这份 HTML 本来就会被知乎、头条、搜狐、WordPress、Ghost 等多个 HTML 平台复用。为什么修复点要上移如果根因来自共享 HTML那么把补丁留在单个平台里只能解决局部问题微信安全了其它 HTML 平台仍然可能收到带结构空白的内容新平台以后还得再补一次维护会退化成“哪个平台先炸就补哪个平台”。而把修复上移到 markdownToHtml 出口之后收益会直接放大marked 路径和 fallback 路径一起生效所有共用渲染链的 HTML 平台自动继承preview 和正式发布更容易保持一致以后扩平台时不用重新回忆历史坑补在哪。这次到底压掉了什么OmniPost 新增的 collapseStructuralWhitespace 并不是粗暴删掉所有换行而是只处理结构标签边界上的空白例如ul、ol、table、thead、tbody、tr开标签后的空白这些容器闭标签前的空白/li、/tr、/td、/th之后到下一个标签之间的空白。这类 whitespace-only 文本节点对守规范的 HTML 消费方来说本就应该被忽略但富文本编辑器未必按浏览器规则解释所以提前清理更稳。为什么不会误伤代码块这次修复最关键的边界是“清结构空白”不能伤到代码块。仓库测试里专门补了两类断言列表/表格结构标签之间不得再有空白代码块里的换行不能被破坏。所以目标不是“压缩整份 HTML”而是只清掉最容易被编辑器误解释的结构空白。代码文本本身仍然会保留。为什么微信适配器里还留了一道兜底因为还有一条路径可能绕过 markdownToHtml用户可以直接提供 article.html。于是这次改动没有把 weixin 里的逻辑彻底删掉而是让它委托共享函数专门兜住用户直供 HTML 的场景。这个分层值得记住默认路径的问题在共享层修绕过共享层的特殊输入在适配器里留兜底。一个很值得复用的判断规则如果多个下游共享同一份中间产物而问题来自这份中间产物的结构噪声那么优先在产物出口统一净化而不是在每个下游各自容错。这类修法对内容分发工具特别值钱因为它一次解决的不是某个平台的单点 bug而是一整条内容管线的未来维护成本。常见问题为什么不只修微信因为问题不是微信独有字段而是共享 HTML 输出里的结构空白。既然多个平台都吃同一份 HTML就应该优先在共享出口统一处理。所有 HTML 平台都会出空列表项吗不一定。更准确地说是平台编辑器行为并不完全可预测所以提前做防御性修复更稳。把空白压掉会改变语义吗对守规范的消费方来说这些结构边界上的空白本就应该被忽略所以通常是语义无损的。真正需要保护的是代码块和正文文本而测试已经把这个边界锁住了。preview 和这次修复是什么关系preview 解决的是“你看到的内容像不像将要提交的内容”这次修复解决的是“平台编辑器会不会把结构空白错认成内容节点”。本文首发于 OmniGoAI 官网https://omnigoai.com/zh/blog/omnipost-whitespace-fix-at-render-exit/ ——OmniPost把内容一键分发到 30 平台。