# 用 Bun WebView 给博客搭了一个 Mermaid 渲染引擎

日期: 2026-06-19T09:28:47Z
摘要: 用 Bun 内置的 WebView API 替代 Playwright，搭了一个 tldraw 渲染 Mermaid 的工具。从 Sunil Pai 的方案出发，走通了一条不需要额外浏览器依赖的路。
关键词:
- Bun.WebView
- Mermaid
- tldraw
- SVG
- 博客工具
- 前端工程

---

写博客的人都有一个共同经历：想在文章里画一张架构图，要么打开 Figma 拖半小时，要么截图贴上去丑得不行。

Mermaid 解决了「文本即图表」的问题，你写几行 DSL，它给你渲染成图。但它有个尴尬的地方——运行时渲染需要加载 Mermaid 的 JS 库，而构建时渲染又需要一个浏览器环境。

Sunil Pai 给了一个漂亮的答案。在他的博客[never waste a token](https://github.com/threepointone/sunilpai-dev/commit/f4bd28a11a6eb4d9f514f13df35d4ca340f5d8d3)那篇文章里，他附带了一个工具：用 @tldraw/mermaid 把 Mermaid 代码块转换成 tldraw 形状，然后通过 Playwright 在构建时导出 SVG。结果就是那些漂亮的手绘风格流程图，light/dark 模式都自动生成好。

我看完的第二天，决定自己也搭一套。但又不想装一个 Chromium。

Bun 内置了 WebView API。macOS 上它用系统自带的 WKWebView，Linux 和 Windows 上驱动 Chrome 或 Edge。关键是不需要额外安装浏览器——系统自带的就够了。

第一版很简单：写一个 React 组件，加载 tldraw editor 和 @tldraw/mermaid，在 Harness 脚本里通过 Bun.WebView 创建窗口、加载页面、注入 Mermaid 源码、调用 createMermaidDiagram 渲染、用 getSvgString 导出 SVG。十分钟就跑通了。

但工具和原型之间差了两个「嗯？」。

第一个问题是字体。tldraw 有自己的手绘字体 tldraw_draw，内嵌在 SVG 里当 base64 woff2 占了将近 200KB。 对于博客用图来说，手绘风格不是必须的。直接去掉 @font-face 块，字体 fallback 到系统 sans-serif，中文还能正常显示。

第二个问题是 SVG 太大。每个 foreignObject 里的 div 都带了一个包含了所有 CSS 属性的 style 属性。这些是浏览器默认值，在 SVG foreignObject 里没有任何意义。解析 style 字符串，只保留 font-family、color、text-align 等必要属性，其余全扔掉。

两步下来，313KB 的 SVG 变成了 24KB。

第三个问题是布局。@tldraw/mermaid 在渲染 TD 方向的 flowchart 时，不会真的把节点纵向排列。我试了 graph TD、flowchart TD、甚至手动指定 direction TB，tldraw 的渲染器都忽略了。节点永远从左到右排开，宽度轻易突破 2000px。

最后的选择是：接受 LR 布局，简化节点文字，让 24KB 的 SVG 在博客的 max-width: 640px 列宽里自适应缩放。实际效果够用。

第四个是不起眼但值得说的：SecurityError。想通过 canvas toBlob 把 SVG 转成 WebP，SVG 里的 foreignObject 会污染 canvas，浏览器直接抛异常。换成 WebView screenshot 又发现 macOS 的 WKWebView 不支持 webp 格式。所以最终保留 SVG 输出。

工具做完了，三种输入方式：

```bash
bun run mermaid arch.mermaid        # 从文件
cat arch.mermaid | bun run mermaid    # 从管道
bun run mermaid -- 'flowchart TD\nA --> B'  # 从参数
```

输出一对 SVG，light 和 dark 各一个，直接嵌入博客文章。

回头看看，这个工具的技术栈有点意思：Bun.WebView 做 headless 渲染，bun build 打包前端 bundle，tldraw 做图形引擎，没有 npm 包需要额外安装浏览器。整个流程只用了一个运行时。下图就是这个工具的完整工作流。

![工具工作流](/imgs/bun-webview-mermaid-workflow.svg)

Sunil 的原版用 Playwright 加 Vite 加 Chromium。Bun 的版本把这四个简化为一个。

当然也有代价：macOS 上 WebView 会弹一个窗口再关掉，Linux 才能真 headless。而且 tldraw 本身是个全功能画布编辑器，只为渲染 Mermaid 就打包 10MB 的 bundle 确实有点重。但 bundle 可以缓存，只要不升级 tldraw 就只用打一次。

最后想说，不要因为「这个功能太小不值得写工具」就用手工画图。自动化工具的好处不是省那几分钟，是你可以持续产出风格一致的图，每一篇都用同一套规范。

写一次工具，后面所有文章都跟着享受。

***

相关文章：

-   [如何使用 Bun Webview 实现图片生成](/如何使用-bun-webview-实现图片生成/)
-   [国内云服务器加速 Bun 安装脚本的三种方式](/国内云服务器加速-Bun-安装脚本的三种方式/)
-   [让博客对 Agent 友好](/让博客对-agent-友好/)
