PlantUML 跨工具迁移实战:迁到 D2、Mermaid、Draw.io 的工作流与陷阱

puml.online

团队图标准化时常常要重新选型,PlantUML 迁到 D2 / Mermaid / Draw.io 是常见操作——这一篇整理迁移实战:哪些图能自动转、哪些必须手写、CI 怎么验证、什么时候别迁。

为什么要迁?

经常出现「我们的团队换栈了」:

  • Java 团队 → LangChain → LLM 团队 → D2 + Markdown 是新默认
  • 数据团队 → 全公司图渲染迁移到 Mermaid(GitHub 原生)
  • 设计协作 → 用 Figma-like 的 Draw.io 替代 PlantUML
  • 「不想依赖 JVM」 → 迁 Mermaid / Graphviz

迁之前先要回答:是技术原因还是「心智成本」原因?PlantUML 的图是「数据」,迁是「数据迁移」——损失细节是必然的。

决策框架:该不该迁

判断维度 不迁
团队规模 <10 人 >30 人
图数量 <50 张 >300 张
图类型分布 80% 流程图 多为 UML/UML 子集
CI 渲染依赖 可变 公司内部已有 plantuml server
设计协作 设计团队主导 工程团队主导
CJK / 复杂字符 重要 不重要
维护期 <6 个月 长期(一两年)

如果不迁

  • 维护现有 PlantUML → 升级到 TeaVM WASM → 在浏览器本地渲染,完全脱离 JVM
  • 维护 plantuml server → 团队 SSR 模式,0 客户端依赖

如果:继续往下看。

PlantUML → Mermaid

自动转换有限

Mermaid 不直接读 PlantUML——需要转换。原因:PlantUUM 和 Mermaid 语法差异大:

概念 PlantUML Mermaid
声明 @startuml ... @enduml ```mermaid\n...\n ```
方向箭头 Alice -> Bob Alice ->> Bob
异步 Alice ->> Bob Alice ->> Bob (相同)
class User class User { }
注释 note left of X Note over X
时序编号 (无原生) autonumber

手工转换示例

PlantUML sequence:

1
2
3
4
5
6
7
8
9
10
11
12
13
@startuml
participant "用户" as U
participant "前端" as F
participant "后端" as B
database "数据库" as DB

U -> F: 点击登录
F -> B: POST /api/login
B -> DB: SELECT * FROM users WHERE email=?
DB --> B: result
B --> F: 200 token
F --> U: 跳转到首页
@enduml

Mermaid sequence(手工翻译):

1
2
3
4
5
6
7
8
9
10
11
12
sequenceDiagram
participant U as 用户
participant F as 前端
participant B as 后端
participant DB as 数据库

U->>F: 点击登录
F->>B: POST /api/login
B->>DB: SELECT * FROM users WHERE email=?
DB-->>B: result
B-->>F: 200 token
F-->>U: 跳转到首页

半自动工具

  • puml2mermaid —— 社区包,覆盖率约 50%
    • ✅ sequence diagram 简单图
    • ✅ class diagram(粗略)
    • ❌ state diagram
    • ❌ component diagram
    • ❌ 嵌套 package / skinparam

实际体验:1 张图花 2 分钟手写 vs 用工具 5 分钟但要反复补多数情况下手写更快

PlantUML → D2

D2 自身提供 plantuml import

D2 官方在 d2 v0.6+ 支持 d2 读 plantuml

1
d2 --plantuml=path/to/diagram.puml out.svg

只支持一种输出方向:puml → D2 等价源码后由 D2 自己渲染。原生转换质量:

  • ✅ sequence diagram 基本
  • ✅ class diagram 基本
  • ⚠️ activity 图丢 if/else 嵌套
  • ❌ state diagram 直接报错

转换后的 D2 代码长这样

原 puml sequence:

1
2
Alice -> Bob: hi
Bob --> Alice: hi back

D2:

1
2
3
shape: sequence_diagram
Alice -> Bob: hi
Bob -> Alice: hi back

D2 用 shape: sequence_diagram 声明类型。

半自动 vs 手写

复杂图(>30 节点、嵌套 package):直接手写 D2,工具转换只对简单图有用

用 D2 自动转换的注意事项

D2 的 plantuml 解析对冒号、引号、CJK字符敏感:

1
2
Alice -> Bob: 包含:冒号  # ❌ D2 解析为多个 message
Alice -> Bob: "包含:冒号" # ✅ 引号包起来

所有 PlantUML 的「消息含特殊字符」都需要在迁移前 quote。

PlantUML → Draw.io

Draw.io 是 XML 格式,PlantUML 没有直接转 Draw.io 的官方工具。

手工工作流

1
2
3
4
# 1. 用 PlantUML 渲染成 SVG
plantuml -tsvg diagram.puml
# 2. 在 Draw.io 里 Import from SVG
# Draw.io → File → Import from Device → diagram.svg

Draw.io 会保留大致布局,但样式 / 类继承 / 注释全丢——通常不值得这么转。

什么时候迁到 Draw.io

  • 需要团队成员手动微调位置
  • 需要画「流程图 + 矩形 + 箭头」混合的非标准图
  • 需要引用形状库 / 模板
  • 不愿用代码编辑器

Draw.io 的核心优势是「所见即所得」,一旦迁过去就别想回来用 PlantUML 编辑——Source 已丢了。

PlantUML → Graphviz DOT

学术 / 自动化场景常见。开源工具:

1
2
3
# https://github.com/yegor256/plantuml2dot
java -jar plantuml2dot.jar diagram.puml > diagram.dot
dot -Tsvg diagram.dot > diagram.svg

支持:

  • ✅ component diagram
  • ✅ class diagram 简单图
  • ⚠️ sequence diagram 转出来的 graph 很丑(DOT 没有时序概念)

各图类型的迁移难度

图类型 PlantUML → Mermaid PlantUML → D2 PlantUML → Draw.io
sequence 中(手动) 低(官方) 高(手工导入 SVG)
class
state 高(无原生等价)
activity
component 低(无) 低(无)
usecase
object 中(.classDiagram 模拟)
ER
gantt 中(mermaid 原生支持)
mindmap 低(双方均原生)

结论

  • sequence / class → Mermaid / D2 双开箱可用,迁移成本最低
  • state / activity / usecase → 任何工具都差,别迁,保持 PlantUML
  • mindmap → 任何工具都行

迁移工作流(真实推荐)

步骤 1:清点现状

1
2
3
# 列所有 puml 文件
ls docs/diagrams/*.puml > inventory.txt
wc -l inventory.txt # 总数
1
2
3
4
5
# 列每张图的图类型
for f in docs/diagrams/*.puml; do
type=$(grep -m1 "^@start\(uml\|sequence\|state\|class\|activity\|component\|deployment\|usecase\|object\|er\|gantt\|mindmap\|wbs\|json\|yaml\)" "$f" | sed 's/@start//' )
echo "$f: $type"
done > types.txt

步骤 2:按图类型分组迁移

1
2
3
4
5
6
# 比如 sequence 迁 Mermaid
while read -r file; do
echo "=== $file ==="
cat "$file"
echo "---"
done < <(grep "sequence" types.txt | cut -d: -f1)

每张图手工翻译 → 写 .mermaid 文件 → 用 mermaid CLI 验证。

步骤 3:CI 验证一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 渲染 → 比较「信息是否一致」
plantuml -tsvg diagram.puml > /tmp/puml.svg
# Mermaid 渲染
mmdc -i diagram.mmd -o /tmp/mm.svg

# 比较结构(节点数、边数)
puml_nodes=$(grep -c "<rect\|<circle\|<ellipse" /tmp/puml.svg)
puml_edges=$(grep -c "<path.*stroke" /tmp/puml.svg)
mm_nodes=$(grep -c "<rect\|<circle\|<ellipse" /tmp/mm.svg)
mm_edges=$(grep -c "<path.*stroke" /tmp/mm.svg)

if [ "$puml_nodes" != "$mm_nodes" ] || [ "$puml_edges" != "$mm_edges" ]; then
echo "❌ 节点 / 边 数不一致: puml($puml_nodes/$puml_edges) vs mermaid($mm_nodes/$mm_edges)"
exit 1
fi

CI 通过 → 迁移完成。

步骤 4:双轨并行期

迁完不要立刻删 PlantUML 文件:

1
2
3
4
5
6
7
docs/diagrams/
├── puml/
│ ├── system.puml # 旧
│ └── auth.puml
└── mermaid/
├── system.mmd # 新
└── auth.mmd

3 个月后确认 mermaid 版本稳定使用,再删除 puml。

啥时候别迁

下面这些场景强烈不建议迁

  1. 大型 UML 项目(>50 张 UML 静态图)—— PlantUML 是行业标准
  2. CI 已有 PlantUML server —— 没有迁移的迫切性
  3. 图已被反向工程(Java → UML) —— Draw.io 无法反向
  4. 需要 !include / !function 等 PlantUML 独有特性 —— 别的 DSL 都没
  5. CJK 内容 + 大图 —— PlantUML + Noto 字体组合目前最稳

反向迁移(D2/Mermaid → PlantUML)

有时候「D2 用了 1 年又想换回来」或者「团队合并时图风格统一」。

D2 → PlantUML

D2 官方提供 d2 –plantuml output 反向 generate,但只输出 fragment,不是完整 .puml。

实际做法:手写或写脚本扫 D2 syntax tree。

1
2
3
4
5
6
7
8
9
10
11
12
13
# scripts/d2_to_puml.py
import re, sys

def d2_seq_to_puml(d2_code):
lines = d2_code.split("\n")
puml = ["@startuml"]
for line in lines:
m = re.match(r"^(\w+)\s*->\s*(\w+)\s*:\s*(.+)$", line)
if m:
src, dst, label = m.groups()
puml.append(f'{src} -> {dst}: {label}')
puml.append("@enduml")
return "\n".join(puml)

Mermaid → PlantUML

无官方工具,社区脚本:

实际不如手写。

一组迁移小脚本

一键 puml → mmd 试错(在仓库里加一个工具)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# scripts/try-migrate.sh
# 用法: ./try-migrate.sh docs/diagrams/auth.puml
set -e
file=$1
name=$(basename "$file" .puml)
echo "@startuml" > /tmp/test.puml
cat "$file" >> /tmp/test.puml
echo "@enduml" >> /tmp/test.puml
plantuml -tsvg /tmp/test.puml

# 手工写 .mmd 文件(参考 hexo blog 的 mermaid 块)
# 然后 mmdc -i auth.mmd -o auth.svg

diff <(node svg-info.js /tmp/test.svg) <(node svg-info.js auth.svg)

实际 80% 是手工。

落到 puml.online 项目的具体决策

我们的项目不需要迁:

  • 当前主力图类型:state、class、sequence 各 5-8 张
  • CI 已经有 hexo generator 渲染 PlantUML
  • CJK + 中文 markdown 注释密集
  • 图源数量,会继续增长

迁出去没收益——迁完还得回来。

用户的项目:迁之前先看看上面的决策表。

小结

  • PlantUML → Mermaid:简单图 1:1,状态机/活动图差很多
  • PlantUML → D2:官方反向 import,但只覆盖基础图
  • PlantUML → Draw.io:本质「导入 SVG」+ 重新调整,source 丢失
  • 迁移代价 80% 是「手工重写」不是「自动转换」
  • 多数情况下别迁——PlantUML 是最稳的 UML DSL

下一步

  • 标题: PlantUML 跨工具迁移实战:迁到 D2、Mermaid、Draw.io 的工作流与陷阱
  • 作者: puml.online
  • 创建于 : 2026-07-30 12:00:00
  • 更新于 : 2026-08-14 21:34:29
  • 链接: https://puml.online/blog/plantuml-migrate-to-d2-mermaid/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。