Forum tooling suggestion: Mermaid diagram support for technical posts

Hi everyone,

A small forum tooling suggestion: would it be worth considering Mermaid diagram support on Nervos Talk?

From what I can see, many technical posts, especially around protocol flows, transaction construction, contract architecture, channel state transitions, or developer tooling, would benefit from small diagrams. They can make the underlying idea much easier to follow.

At the moment, the usual workaround is to export Mermaid diagrams as images and upload them as attachments. That works, but it has a few drawbacks:

  • diagrams become harder to edit after feedback, and small corrections require generating and uploading a new image;
  • reviewers cannot easily copy, inspect, or suggest changes to the diagram source;
  • the forum accumulates extra image attachments for things that are fundamentally text-based.

If Mermaid were supported, authors could keep diagrams as plain text in the post. That would make technical explanations easier to maintain and review, and probably lighter for diagram-heavy posts.

Of course, this may or may not be practical within the current Discourse setup.

Curious whether others would find this useful as well.

10 Likes

A useful follow-up here: Discourse already maintains an official Mermaid theme component:

It supports Mermaid code fences directly in posts, composer preview, dark-mode rendering, fullscreen viewing, and controlled syntax errors. The diagrams are rendered client-side from the textual source, so there is no external rendering service or image-upload workflow involved.

This means the proposal may not require much custom development.

4 Likes

I support this, just I wonder how it would interplay with Babel our translation layer, which if you notice already disable some Discourse-native features:

1 Like

Hey Phroi, thank you for bringing up this, I actually had gone through both repos earlier this week and i think so far the two plugins are generally compatible at the markdown layer (Mermaid blocks should survive translation end-to-end), though they share a real client-side caveat that’s the same root cause as the bare-link rendering difference you flagged.

Maybe a possible fix could be on the Babel Reunited side, by replacing {{htmlSafe this.currentContent}} with a render through <CookedHtml> (or manually trigger api.decorateCookedElement on the wrapper after insertion) so the standard decoration pipeline runs.

And just mentioning this, it seems mermaid labels will not be translated if both plugins are deployed in a vanilla manner, because Babel Reunited seems to treat ```mermaid as an opaque code block, the text inside Mermaid node labels (e.g. A[用户点击发送]) is passed through verbatim, even in the translated view. A Chinese post with Chinese-labelled diagrams, when translated to English, will still have Chinese text inside the diagram. Maybe some decision should be made about this should we explore the direction.

mermaid 支持是个好想法。@ArthurZhang 二楼找到官方的 discourse-mermaid-theme-component 很关键,基本不用自研;四五楼指出的和 Babel 不兼容的问题也是真实存在的。

我这几天研究了一下代码,发现问题的根源其实在 Babel 自己的实现上,mermaid 只是恰好第一个撞上来的。稍微解释一下,因为涉及 Discourse 的渲染机制,不了解的话不太容易看出问题在哪。

Discourse 正文的帖子存的是 markdown,服务端转成 HTML。但这个 HTML 只是骨架,有些功能是在浏览器里渲染之后再由JS 加工一遍才有的,这一步叫装(decoration):代码块加复制按钮、数学公式排版、spoiler 加模糊遮罩、日期转本地时区。mermaid 也是这么工作的——把 ```mermaid 代码块整个替换成一张 SVG 图。

在普通帖子正文这条渲染路径上,这些装饰都由 core 的同一个组件统一执行,渲染完正文就把注册过的装饰器依次跑一遍。

Discourse 让插件往界面里插内容的机制叫 plugin outlet。正文那个位置的 outlet,默认内容就是这个组件。这里有个容易踩的规则:插件注册进去之后,默认内容不会自动保留,必须在模板里写 {{yield}} 才会渲染。

Babel 现在的问题

Babel 的语言标签注册进了这个 outlet,但没有 {{yield}},正文是自己直接注入 HTML 的。等于把core 那个组件整个摘掉了,那一次装饰器执行从来没发生过。

所以准确说不是"mermaid在译文里不渲染",而是所有依赖装饰的功能,在插件启用后的所有帖子上都不工作,看原文时也一样

我测过,判据是代码块的复制按钮(只由 core 装饰器在客户端添加):插件关闭时按钮在,开启时按钮消失,两种情况下代码块 HTML 都完好——只是装饰没跑。

这里要区分两层问题

@phroi 三楼发现的裸链接显示差异是个有效线索,但它和上面这个不是同一个根因,这点我要说清楚:

  • 客户端这一层(就是上面说的):装饰管线没跑,影响 mermaid、代码块按钮、公式、spoiler
    等。范围最广,还没修。
  • 服务端这一层:译文生成后没有走完整的 cooked 后处理,导致 onebox 链接预览不展开、图片缺少 lightbox 外层结构。这是 phroi 看到那个差异的真正原因,这个修复今天已经上线.

图片的点击放大需要两层都到位——服务端生成结构,客户端绑定交互。

打算怎么改

核心思路是把渲染交回 core,分两种情况:

  import PostCookedHtml from "discourse/components/post/cooked-html";

  {{#if (eq this.currentLanguage "original")}}
    {{yield}}
  {{else}}
    <PostCookedHtml
      @post={{this.post}}
      @cooked={{this.currentContent}}
      @decoratorState={{@decoratorState}}
    />
  {{/if}}

这段整个替换掉现在那个手工注入的容器(core 的组件本身就会带上 cooked 这个 class,不用再包一层)。

原文视图直接 {{yield}},用 core 原封不动的渲染,最大程度恢复 Discourse 原有行为、把回归风险降到最低。译文视图仍然走 core 的组件,只是把正文换成译文——它本来就支持传入覆盖,这点是现成的。

改了的好处
这次前端修复可直接免费获得很多标准插件的支持(大部分情况无需再做针对性开发):

  • mermaid,装上主题组件即可,包括全屏
  • 代码块复制与全屏按钮
  • 数学公式、spoiler、local-dates、checklist、lazy-videos
  • @提及装饰、引用展开、链接计数、hashtag 装饰、details 折叠状态

已经由服务端那层修复覆盖的:onebox 链接预览展开、图片 lightbox 结构。

再往后,基于标准装饰管线、且源码标记能在翻译中完整保留的插件,一般就不需要 Babel 再专门适配了。(依赖自定义 BBCode 或 post 元数据的插件仍可能需要单独处理,比如 Poll 这类。)


今天刚部署了翻译的另一批修复(另一个帖子里 @phroi 报的长帖格式损坏那批)。渲染这块我打算单独修改,不跟 mermaid 绑在一起——它修的是Babel 自己的既有缺陷,本来就该修。顺序是先把渲染改对,然后装 mermaid 组件基本就能直接用。

至于 @ArthurZhang 五楼提的图内文字翻译,我倾向先不做。mermaid 语法对结构敏感,节点ID、连线、各种图表类型的标签写法都不一样,让模型翻整块很容易把图翻成语法错误、直接渲染失败, 那比图里文字没翻译更糟。以后要做的话会限定图表类型、只提取标签文本,并且加结构校验——结果和原图对不上就丢弃翻译保留原图。

感谢 @ArthurZhang @phroi

5 Likes

多谢 Terry 阅读这项提议并花时间解释 Discourse & Babel 的渲染处理机制。我也学到了不少。

1 Like