Mermaid 架构图语法实测:flowchart / architecture-beta / C4 / block-beta 怎么选
Mermaid 不只是画流程图。11.x 版本里有好几种专门的架构图语法,但文档零散、中文资料少,而且各有各的解析脾气。
本文用同一个部署拓扑做横向对比。除了
architecture-beta(原因见第 3 节),其余语法都在本博客实际渲染通过;所有代码块都用mermaid@11.16.1校验过,解析失败的写法也一并列出并说明原因——这些坑不写出来,你照抄就会收获一个红色错误框。
1. 先看结论
| 语法 | 定位 | 语义强度 | 中文标题 | 本站可渲染 |
|---|---|---|---|---|
flowchart | 通用流程图,什么都能画 | 弱(只有连线) | ✅ 直接写 | ✅ |
architecture-beta | 云/服务架构图,有分组与方位概念 | 中 | ⚠️ 必须加双引号 | ❌ 见第 3 节 |
C4Context / C4Container | C4 模型,人/系统/容器分层 | 强(区分角色) | ✅ 直接写 | ✅ |
block-beta | 块状栅格布局,接近系统框图 | 弱 | ✅ 直接写 | ✅ |
一句话选型:要语义、给人讲架构 → C4;只是想连线 → flowchart;想摆成方块矩阵 → block-beta。(architecture-beta 语法本身不错,但在本站渲染不出来,只能当参考。)
2. 基准拓扑
后面三种能渲染的语法画的都是这一个东西,方便对比表现力:
客户端 → Nginx(反向代理) → FastAPI 1 / FastAPI 2 → PostgreSQL
↘ Redis先用最熟悉的 flowchart 打个底:
能用,但表达不了「哪几个组件属于同一层」——只能靠命名暗示,或者上 subgraph:
subgraph 解决了分组,但布局仍然由渲染引擎自动决定,你控制不了方位。
3. architecture-beta:只作语法参考
这是 Mermaid 专门为服务架构设计的语法,概念上确实最像「架构图」:有分组、方位和内置图标。
但在本站渲染不出来,所以本节不提供在线示例
实测在博客的 VitePress 环境(vitepress-plugin-mermaid)中,architecture-beta 代码块浏览器端不出图,页面相应位置是空的。更坑的是:
- 构建阶段完全静默:
npm run build通过,日志无任何报错 - 离线用
mermaid.parse()校验也通过(语法没问题) - 甚至用 jsdom 打桩跑
mermaid.render()都能产出 SVG
只有真实浏览器渲染这一步会失败,且不报错。 所以它没法在本站用来做图示。
想用这套语法的话,建议去 Mermaid Live Editor 或本地 Markdown 预览器里先验证效果,再决定要不要引入。下面只保留语法备忘与踩坑记录。
3.1 语法速查
| 元素 | 写法 | 说明 |
|---|---|---|
| 分组 | group <id>(<icon>)["标题"] | 画成一个大框,服务挂在里面 |
| 服务 | service <id>(<icon>)["标题"] | 一个节点 |
| 归属分组 | service ... in <group-id> | 写在服务定义末尾 |
| 分叉点 | junction <id> | 让一条线分成多条 |
| 无向边 | a:L -- R:b | |
| 单向边 | a:L --> R:b | 箭头指向 b |
| 反向边 | a:L <-- R:b | 箭头指向 a |
| 双向边 | a:L <--> R:b | 两端都是箭头 |
| 方位 | L / R / T / B | 左 / 右 / 上 / 下,贴在节点 id 后面 |
方位是它设计上最有价值的地方:api1:B -- T:db 表达「FastAPI 1 的下方连到数据库的上方」,渲染时按这个相对位置排。可惜本站用不上。
3.2 三个解析坑
即使将来换个环境用,这三条也得先知道——它们会让解析直接失败:
坑一:中文标题必须加双引号
architecture-beta 的标题词法只接受 ASCII 字符。直接写中文,解析器会在 [ 处直接报错:
architecture-beta
group g(cloud)[云] ← ❌ Lexer error: unexpected character: ->[<-
architecture-beta
group g(cloud)["云"] ← ✅ 加双引号即可英文标题不受影响,带空格也 OK(["Edge Layer"] 没问题)。但只要有 CJK 字符,必须加引号。
坑二:节点 id 只能是 ASCII
service 服务(server)[Server] ← ❌ 同上,id 处就报错
service svc(server)["服务"] ← ✅ id 用英文,中文放标题坑三:内置图标只有 6 个
(cloud)、(server) 这类括号里的是内置图标名。实测可用的只有:
| 图标 | 适用 |
|---|---|
cloud | 分组框、云 |
server | 应用服务、Web |
database | 数据库 |
disk | 存储、缓存 |
internet | 客户端、外部网络 |
blank | 占位(不画图标) |
写别的名字不会报错,但图标位置会是空的。想要更多图标,得用 mermaid.registerIconPacks() 自己注册图标包。
4. C4:语义最强,适合正式架构文档
C4 模型把架构拆成「人 / 系统 / 容器 / 组件」四层,Mermaid 支持上下文图和容器图。它的价值在于节点类型本身携带语义——一眼能看出哪个是人、哪个是数据库。
常用元素:
| 元素 | 含义 |
|---|---|
Person(id, "名称", "描述") | 使用者/角色 |
System(id, "名称", "描述") | 外部系统(上下文图用) |
Container(id, "名称", "技术", "描述") | 应用容器 |
ContainerDb(id, ...) | 数据存储 |
Rel(从, 到, "关系", "技术") | 带方向的关系 |
Boundary(...) | 画一个边界框 |
中文完全不用引号,这点比 architecture-beta 友好。缺点是布局完全自动,节点多了容易乱;而且节点样式由 C4 主题决定,可定制性低。
5. block-beta:块状栅格布局
block-beta 把图画成显式栅格,用 columns N 指定列数,元素:N 表示跨 N 列。适合画分层拓扑、能力矩阵这种规整的东西。
也可以嵌套 block 做分组:
它的优势是布局完全可预测(你说了算,不是引擎说了算),适合做「系统框图」;代价是连线能力弱,复杂依赖关系表达不了。
6. 同一拓扑,四种画法对比
| 画法 | 分组 | 方位可控 | 内置图标 | 中文标题 | 连线能力 | 本站可渲染 |
|---|---|---|---|---|---|---|
flowchart | 需 subgraph | ❌ | ❌ | ✅ | 强 | ✅ |
flowchart + subgraph | ✅ | ❌ | ❌ | ✅ | 强 | ✅ |
architecture-beta | ✅ | ✅ | ✅ 6 个 | ⚠️ 要引号 | 中 | ❌ |
C4Container | ✅ Boundary | ❌ | 图标随类型自动 | ✅ | 中 | ✅ |
block-beta | ✅ block | ✅ 栅格 | ❌ | ✅ | 弱 | ✅ |
7. 选型建议
- 给非技术同事讲系统长什么样 →
C4Container,节点类型自带语义,一眼能分清人和数据库。 - 正式架构文档 / 需要说明「谁调用谁」 →
C4Context+C4Container,分层语义是它的核心价值。 - 画流程、状态、时序 → 老老实实用
flowchart/stateDiagram/sequenceDiagram,别硬套架构图语法。 - 需要严格对齐的系统框图 →
block-beta。 - 快速表达依赖关系 →
flowchart,成本最低。 → 概念上最合适,但本站渲染不出来(第 3 节),只能去 Mermaid Live Editor 用。architecture-beta
8. 坑点汇总
| 现象 | 原因 | 解决 |
|---|---|---|
Lexer error: unexpected character: ->[<- | architecture-beta 标题只接受 ASCII | 中文标题加双引号 ["中文"] |
| 同上,但报错位置在 id 处 | 节点 id 也要求 ASCII | id 用英文,中文写进标题 |
architecture-beta 图标位置空白 | 用了 6 个内置图标之外的名字 | 换 cloud/server/database/disk/internet/blank,或注册自定义图标包 |
architecture-beta 页面空白,构建和校验却全绿 | 浏览器端渲染失败但不抛错、不提示;npm run build 静默通过,mermaid.parse() 也通过,jsdom 打桩甚至能产出 SVG | 交付前在真实浏览器里过一眼;architecture-beta 在本站直接用不了 |
想验证语法但 Node 里报 DOMPurify.addHook is not a function | Node 无 DOM,dompurify 导出的是工厂函数 | 给 dompurify 打桩(补 sanitize/addHook 空实现)+ 设 securityLevel: 'loose' |
两条经验
- 离线校验只能证明「语法对」,证明不了「能渲染」。
parse()过 ≠ 浏览器出图,architecture-beta就是反例。渲染类问题最终得在浏览器里确认。 - 仓库里已经装了
mermaid,可以写脚本把所有 ```mermaid 代码块抽出来逐块await mermaid.parse(src),至少把语法错误挡在提交之前。
9. 什么时候不该用 Mermaid
Mermaid 的定位是「说明型」图示:可 diff、可维护、跟随主题换色。但它有个硬边界——美术可控度低。布局由引擎决定,你改不了节点的精确坐标、圆角、渐变、投影。
如果你的图属于「展示型」:要做封面图、要打印、要拿到站外复用、要精确控制视觉,那就该用手写 SVG:
上面这张就是手写的 SVG(源码在 docs/notes/tools/images/wsgi-vs-asgi.svg,157 行)。它和 Mermaid 的分工是:
| Mermaid | 手写 SVG | |
|---|---|---|
| 可 diff | ✅ 纯文本 | 🟡 XML,diff 一般 |
| 跟随深浅色主题 | ✅ 自动 | ❌ 配色写死 |
| 改动成本 | 改一行 | 调坐标 |
| 美术可控度 | 低 | 高 |
| 打印 / 站外复用 | ❌ 依赖 JS | ✅ 哪都能打开 |
结论:文章内的说明性图示用 Mermaid,撑门面的架构总图用手写 SVG。
10. 小结
| 要点 | 说明 |
|---|---|
architecture-beta 本站用不了 | 语法本身不错(有分组、方位、内置图标),但浏览器端渲染失败且不报错,只能去 Mermaid Live Editor 用;语法备忘与解析坑见第 3 节 |
| C4 语义最强 | 节点类型自带含义,适合正式架构文档,中文无需引号 |
block-beta 布局可控 | 栅格由你说了算,适合系统框图,连线能力弱 |
flowchart 依然是默认选择 | 成本最低、能力最全,只是分组和方位要妥协 |
| 语法对 ≠ 能渲染 | mermaid.parse() 通过不代表浏览器出图,渲染问题最终得在真实浏览器确认 |
| 构建不会帮你发现 Mermaid 错误 | 构建期不解析 Mermaid,写错也不报,离线 parse() 至少能挡住语法错误 |
| 展示型图别硬用 Mermaid | 美术可控度是硬边界,该上 SVG 就上 SVG |