很多团队的流程图,一直停留在“画一遍、改一遍、再重画一遍”的状态。产品逻辑变了,流程图要重画;需求文档更新了,架构图要重画;评审会上大家对着图争论,回头发现图又落后于代码。真正的问题不是画图的技巧,而是流程图的存储形式不对:它被存成了没法 diff、没法版本管理、没法自动生成的画布文件。这次我们看的这个项目思路,标题就直接点出了解法:Mermaid flowcharts you don't have to redraw in a diagram editor,意思是让 Mermaid 流程图以代码形式存在,渲染结果交给 Mermaid,而不是再回到 diagram editor 里手工重绘。
Mermaid 是一套基于 JavaScript 的图表渲染引擎,用类似 Markdown 的文本语法描述流程图、时序图、类图、状态图、ER 图、甘特图等。写的是代码块,出的是矢量图。开发者和文档工程师维护的是 .mmd 文件或 Markdown 中的 mermaid 代码块,图的逻辑结构就在文本里,大家可以在 Git 里逐个字符地 review 变更。整个过程不再需要拖拽画布、对齐节点、微调连线。
这篇文章不会只讲概念,重点放在四件事上:第一,Mermaid 流程图如何用代码定义,为什么不需要在 diagram editor 里重绘;第二,本地编辑环境怎么搭,浏览器、VS Code、命令行三个入口怎么选;第三,如何用 mermaid-cli 做批量导出和接口化调用;第四,从语法、渲染、性能到常见坑的完整验证流程。适合读者很明确:后端开发、文档工程师、运维同学,以及所有“画图五分钟、改图半小时”的人。只要有一台普通办公电脑,装好 Node.js,命令行能用,剩下的事就是写语法。
1. Mermaid 核心能力速览
在动手之前,先把 Mermaid 这个方案的能力边界看清楚。下面的表格是把 Mermaid 生态里最常用的几个入口(mermaid.live、mermaid-cli、VS Code 预览插件)放在一起评估的结果,具体版本和细节以实际安装为准,但整体能力分布不会变。
| 能力项 | 说明 |
|---|---|
| 项目类型 | 基于 Mermaid 的代码化图表渲染方案 |
| 核心价值 | 流程图以文本代码维护,渲染与重绘分离,无需手工重画 |
| 支持的图表类型 | 流程图(flowchart)、时序图、类图、状态图、ER 图、甘特图、饼图、用户旅程图、思维导图、时间线等,具体取决于版本 |
| 运行环境 | 浏览器、Node.js、VS Code 扩展、Docker |
| 硬件门槛 | 极低,普通 CPU 即可,无显卡要求 |
| 主要工具 | mermaid.live、@mermaid-js/mermaid-cli、VS Code 预览扩展 |
| 是否支持 API | 支持,命令行为主,也有在线渲染接口和自建服务方案 |
| 是否支持批量任务 | 支持,CLI 可批量转换 .mmd / .md 文件 |
| 输出格式 | SVG、PNG、PDF、HTML 等,按 CLI 参数配置 |
| 适合场景 | 技术文档、架构评审、需求分析、代码注释、CI 文档生成 |
从整个生态看,最成熟的两条路径是:日常编辑用 VS Code 加预览插件,改代码就看到图;自动化场景用 mermaid-cli 批量渲染,接到 CI 流水线里。两条路径都不需要你打开传统的拖拽式画图工具。后面每一章都会围绕这两条路径展开。
2. 适用场景与使用边界
这个思路适合谁,一句话概括:任何需要“图表跟随文档版本一起演进”的人。代码化流程图的收益,在单张图上不明显,在持续变更的文档体系里非常明显。每次需求变更,改的是几行文本,而不是重新拖一遍画布。
具体来说,适合这些场景。第一类是技术方案文档,直接在 Markdown 里内嵌 mermaid 代码块,提交到 Git,评审时看渲染结果,reviewer 能看到流程图逻辑的精确 diff。第二类是接口流程说明,时序图用代码写,接口变更后同步改文本即可,不会出现代码和文档两张皮。第三类是架构图、状态机、ER 图,用代码维护比拖拽对齐更快,最重要的是 diff 可读,哪条连线变了、哪个节点加了,一眼就能看出来。第四类是 CI/CD 自动更新文档,改完代码,流水线自动生成最新图表并发布到内部 Wiki。第五类是博客和知识库,Markdown 直接渲染,发布平台原生支持或插件支持。
不太适合的场景也要说清楚。如果追求像素级视觉设计,比如对外宣传图、UI 交互稿,Mermaid 的可视化定制能力有限,颜色、字体、布局的精细控制都不如专业绘图软件。如果图特别大,几百个节点以上,Mermaid 布局算法容易失控,需要拆图或考虑 Graphviz 等其他方案。如果使用者是完全不碰代码的业务同学,学习成本主要在语法,而不是工具操作,这时候要评估是教语法还是继续用画图工具。
使用边界方面,Mermaid 本身只是纯客户端图表渲染,不涉及数据上传,但工程上要注意合规。在线版 mermaid.live 渲染时靠浏览器本地执行,代码本身会进入页面会话,不要把你公司的敏感架构图贴到不受控的公共服务上。涉及保密项目的架构、账号体系、数据库拓扑、内部域名和 IP,建议一律本地 CLI 渲染。对外发布前,检查节点文本是否包含内部信息片段,这是很多人容易忽略的一步。
3. Mermaid 本地部署与编辑环境准备
先讲环境。Mermaid 对硬件几乎没要求,普通办公机、虚拟机、云服务器都行,不需要 GPU,也不需要大内存。真正要花时间准备的是 Node.js 运行时、包管理器和编辑器,以及 mermaid-cli 导出图片时依赖的无头浏览器内核。
需要准备的核心环境按优先级排列:Node.js,建议安装 LTS 版本,mermaid-cli 基于它运行;npm 或 yarn,随 Node.js 自带 npm;VS Code 编辑器,配合预览插件使用;Chrome 或 Edge 浏览器,用于交互式验证渲染结果;还有一个隐藏依赖,mermaid-cli 导出 PNG/PDF 时通过 Puppeteer 拉起 Chromium 内核,安装 CLI 时会自动拉取,磁盘会多占用几百 MB 到 1GB 左右。
环境准备阶段,先跑一遍通用检查清单:
# 检查 Node.js 是否安装 node -v # 检查 npm 是否可用 npm -v # 检查当前 npm 源,按需切换镜像 npm config get registry如果 node -v 没有输出版本号,先去 Node.js 官网下载 LTS 安装包,一路默认安装,然后重新打开终端再验证。国内网络环境如果 npm 安装依赖经常失败,把 registry 切到镜像源会省很多时间,这一步在做 mermaid-cli 安装之前最好先完成。
关于版本,Mermaid 和 mermaid-cli 都在持续更新,不同版本对语法支持有差异。第一次使用建议直接用最新稳定版,不要拿很老的教程硬套,尤其是子图、方向、样式这些语法在不同版本里的行为不完全一致。项目里如果要复用,建议把 CLI 版本固定下来,避免升级后渲染效果变化导致文档里的图全部换样。
4. Mermaid 安装部署与启动方式
4.1 VS Code 插件方式
这是日常写文档最舒服的入口。在 VS Code 扩展商店搜索 Mermaid,安装 Markdown Preview Mermaid Support 这类预览插件。插件的作用是在 Markdown 预览时,自动识别 mermaid 代码块并渲染成图。
安装后,新建或打开一个 Markdown 文件,写入 mermaid 代码块:
graph TD A[需求分析] --> B[方案设计] B --> C[开发实现] C --> D[测试验收] D --> E[发布上线]按 Markdown 预览快捷键,图表直接渲染。改代码,预览实时刷新,完全不用重画。这就是标题里 don't have to redraw 在编辑环节的体现。整个体验和写 Markdown 一样,是“文本输入加即时反馈”,而不是“拖拽对齐加手动连线”。
4.2 mermaid.live 在线编辑器
如果只想快速验证一段语法,不想本地装任何东西,直接打开 mermaid.live 即可。左边是语法代码,右边是实时渲染结果,顶部可以导出 PNG/SVG,还可以把代码加密后生成共享链接发给同事。这个入口适合三件事:验证新写的语法是否正确,给同事演示某个流程,或者临时画一张小图直接导出用。
需要注意,在线页面渲染确实在浏览器本地完成,但你把共享链接发给别人时,代码内容会经过第三方服务处理。公司内部架构、客户数据、账号体系流程,不要走这个入口。更稳妥的做法是本地 CLI 渲染,导出图片后再发。
4.3 mermaid-cli 命令行方式
批量场景、CI 场景、API 场景,都必须用命令行工具。mermaid-cli 的官方包名是 @mermaid-js/mermaid-cli,安装方式如下:
# 全局安装,方便命令行直接调用 npm install -g @mermaid-js/mermaid-cli # 查看帮助 mmdc -h安装完成后,写一个输入文件 test.mmd:
graph LR A[用户请求] --> B[网关] B --> C[服务A] B --> D[服务B] C --> E[(数据库)]执行转换命令:
# 输出 SVG mmdc -i test.mmd -o test.svg # 输出 PNG,指定背景色和宽度 mmdc -i test.mmd -o test.png -b white -w 1200 # 输出 PDF mmdc -i test.mmd -o test.pdf第一次运行 mmdc 时,CLI 会自动定位或下载 Chromium 内核,如果下载失败,会报 Puppeteer 相关错误。这个问题非常常见,后面排查章节会给方案。命令执行成功后,同目录下会出现对应格式的图片文件,用浏览器打开 SVG 可以确认渲染内容和预期一致。
4.4 Docker 方式
如果不想在宿主机装完整 Chromium,或者需要固定版本跑自动化任务,可以用 Docker 封装 mermaid-cli。社区和官方都有容器镜像,通用做法是把本地目录挂载进容器,再执行 mmdc:
docker run --rm -v $(pwd):/data ghcr.io/mermaid-js/mermaid-cli/mermaid-cli -i /data/test.mmd -o /data/test.svg具体镜像名以你选择的仓库说明为准,上面的命令只是通用示例。Docker 方式的好处是环境隔离、版本固定,不会因为某台机器缺 Node 依赖而失败,适合放进自动化流水线。缺点是多一层容器管理的复杂度,对单机用户来说,直接用 CLI 更省事。
5. Mermaid 基本用法与核心语法:代码绘图代替手工重绘
整个思路成立的关键,是把流程图的“逻辑结构”和“视觉渲染”分离。你在 Mermaid 里描述的是节点和连边关系,布局引擎负责把节点自动摆放、连线自动路由。下面这段代码就是完整的流程图定义:
flowchart TD A[开始] --> B{是否有权限} B -- 是 --> C[进入系统] B -- 否 --> D[返回登录页]这段代码表达的含义非常明确:方向是 TD,即从上到下;节点 A 是矩形,内容为“开始”;节点 B 是菱形,内容为“是否有权限”;B 到 C 的连线标签是“是”,B 到 D 的连线标签是“否”。注意,这里没有定义任何坐标,没有拖动,没有对齐。渲染器根据节点之间的连接关系自动完成布局。
这意味着三个直接收益。
第一,重构图结构时,只改文字和连线,位置不用管。新增一个分支就是在文本里加一行箭头,删掉一个环节就是删一行,视觉布局自动重排。
第二,代码可以放进 Git,提交记录里能看到流程图逻辑的历史变更。流程图和代码一样有版本,一样能回溯,这是画布文件做不到的。
第三,多个文档可以复用同一段节点定义。把公共流程抽成片段,写进各自的文档里,更新时只改一处语义,不用再手工同步多张图。
常用语法要点整理如下:
| 语法 | 作用 |
|---|---|
| graph TD / graph LR / flowchart TB | 定义图类型与方向 |
| A[文本] | 矩形节点 |
| A(文本) | 圆角矩形节点 |
| A{文本} | 菱形判断节点 |
| A --> B | 有向连线 |
| A --- B | 无箭头连线 |
| A -- 标签 --- B | 带标签连线 |
| subgraph 标题 | 子图分组 |
| classDef / class | 节点样式定制 |
这里只列了最常用的部分,完整语法建议参考 Mermaid 官方语法手册。实际书写时,先用 mermaid.live 快速验证一段语法,确认渲染效果后再粘回文档,这段验证过程大概 30 秒,比在画图软件里对齐节点快得多。
6. Mermaid 功能测试与效果验证
环境准备好之后,建议按下面这套流程做一轮功能验证。不用一次全测,按自己的场景挑几项即可。
6.1 基础渲染测试
测试目的:确认 mermaid 代码能正常渲染成图。输入示例为一个带判断分支的流程:
flowchart LR A(输入) --> B{校验} B -->|通过| C[处理] B -->|失败| D[报错]操作步骤很简单。先把代码粘贴到 mermaid.live 左侧,观察右侧是否出现两条分支的流程图;再用 VS Code 的 Markdown 预览验证同一个代码块,确认两种环境的渲染结果一致。预期结果是左右两侧图中,节点文字和连线标签都正常显示,能清楚看出“输入 -> 校验 -> 通过/失败 -> 处理/报错”的完整路径。
常见的失败情况是节点文字包含括号、引号等特殊字符时渲染异常。解决办法是用双引号把节点文字包起来,例如 A["用户 ID (uid)"],这样括号就不会被 Mermaid 当成语法边界。
6.2 时序图测试
测试目的:验证代码描述时序逻辑的能力,这是接口文档里最常见的场景。输入示例:
sequenceDiagram participant U as 用户 participant S as 服务端 participant D as 数据库 U->>S: 登录请求 S->>D: 查询用户 D-->>S: 返回结果 S-->>U: 登录成功预期结果是生成用户、服务端、数据库三个泳道,消息按顺序从上到下排列,返回消息用虚线表示。这个图能直接表达接口调用顺序和异步返回关系,比文字描述直观得多。如果参与角色很多,可以给 participant 加别名,避免长名字把图撑得太宽。
6.3 子图与样式测试
测试目的:验证复杂流程的组织能力,尤其是多个服务或模块的分组展示。输入示例:
flowchart TB subgraph 订单服务 A[创建订单] --> B[扣减库存] end subgraph 支付服务 C[发起支付] --> D[支付回调] end B --> C预期结果是两个子图分别框住各自节点,子图之间的连线从 B 指向 C。如果渲染出来的子图位置不理想,这是布局引擎的常见现象,可以调整子图定义顺序或给子图加 id 来控制。但建议不要在这上面花太多时间,代码化绘图的收益是逻辑维护,不是像素级布局。
6.4 批量文件转换测试
测试目的:确认 CLI 批量处理能力,这决定了能不能接到自动化流程里。先准备一个目录:
diagrams/ ├── login-flow.mmd ├── order-flow.mmd └── deploy-flow.mmd执行批量转换命令:
mkdir -p output for f in diagrams/*.mmd; do mmdc -i "$f" -o "output/$(basename "${f%.mmd}").svg" done预期结果是 output 目录下出现三个 SVG 文件,文件名与输入对应。判断标准是所有文件都能生成,且 SVG 里能看到对应节点文字,没有空图和报错中断。
7. Mermaid 接口 API 与批量任务
Mermaid 的接口能力分三个层次,从简单到可控,按需选择。
7.1 CLI 调用
mermaid-cli 本身就是最稳定的接口,把 .mmd 文件交给 mmdc,得到 SVG/PNG/PDF,适合接进脚本、CI 流水线、文档生成系统。一个简单的 Python 批量调用示例:
import subprocess from pathlib import Path diagrams_dir = Path("./diagrams") output_dir = Path("./output") output_dir.mkdir(exist_ok=True) for mmd_file in diagrams_dir.glob("*.mmd"): out_svg = output_dir / f"{mmd_file.stem}.svg" subprocess.run( ["mmdc", "-i", str(mmd_file), "-o", str(out_svg)], check=True, )这段代码会把 diagrams 目录下所有 .mmd 文件逐个转换为同名 SVG。注意 check=True 表示任一文件失败就会抛出异常,生产环境建议捕获异常并记录日志,避免一个坏文件中断整批任务。
7.2 mermaid.ink 在线接口
mermaid.ink 是把 mermaid 代码编码后通过 URL 获取渲染图片的服务,适合在文档里引用动态生成的图表。请求格式一般是把 mermaid 代码做 base64 编码后拼到 URL 里:
# 先对 mermaid 代码做 base64 编码,再拼接到 URL curl "https://mermaid.ink/img/{base64编码的代码}"在线服务可能随时调整,实际使用前先查看对应服务说明。如果涉及内部流程,不推荐把代码明文放进 URL,一方面有长度限制,另一方面有泄露风险。这个接口更适合公开文档或临时演示。
7.3 自建渲染服务
更可控的做法是自己包一个渲染服务,把 mermaid-cli 包装成 HTTP 接口,输入流程图代码,输出 SVG/PNG。下面是一个 Spring Boot 风格的伪代码,表达“包装 CLI 为 API”的思路:
@PostMapping("/render") public String render(@RequestBody String mermaidCode) throws Exception { Path input = Files.createTempFile("diagram", ".mmd"); Files.writeString(input, mermaidCode); Path output = Files.createTempFile("diagram", ".svg"); Process p = new ProcessBuilder("mmdc", "-i", input.toString(), "-o", output.toString()) .inheritIO().start(); p.waitFor(); return Files.readString(output); }注意这只是伪代码,不是可直接运行的实现。生产环境要加超时、限流、临时文件清理和权限控制,否则每次请求拉起一个 Chromium 进程,并发一高机器就会吃紧。批量任务的工程化建议:输入和输出目录分离,每次任务生成独立日志,单个文件失败不中断整个批次,产物按日期或版本号归档。
8. 资源占用与性能观察
资源占用是很多人在意、但官方文档不细讲的部分,这里单独说。Mermaid 渲染本身非常轻,在浏览器或 VS Code 里渲染一张常规流程图,CPU 和内存占用可以忽略,普通笔记本无压力。真正的资源开销来自 mermaid-cli 导出 PNG/PDF 时拉起的 Chromium 内核,因为它是通过无头浏览器渲染再截图或打印。
观察方法很直接:执行 mmdc 时,另开一个终端用 top 或任务管理器观察 chromium 进程;大图导出 PNG 时,CPU 会短时拉高,这是正常现象;内存占用取决于 Chromium 内核加载,通常几百 MB 级别,具体以本机测试为准。
影响性能的主要因素:
| 因素 | 影响 |
|---|---|
| 节点数量 | 几百个节点以上布局算法耗时明显增加 |
| 输出格式 | PNG 需要渲染后截图,比 SVG 直接输出慢 |
| 图片尺寸 | -w -h 越大,截图耗时越长 |
| 批量数量 | 串行批量会累积等待时间,建议控制并发数 |
| 字体加载 | 离线环境字体缺失会拖慢渲染或导致中文乱码 |
降低开销的方法很明确。不需要位图时一律输出 SVG,SVG 是矢量格式,直接由渲染内核输出,速度快且无失真。PNG 导出的宽度按文档实际需要设置,不要无脑放大。批量任务限制并发,比如同时跑两到三个 mmdc 进程,避免机器卡死。大图建议拆分成多个子图,分别渲染再合并到文档里。
接口服务场景要特别注意,如果每个请求都拉起一个 Chromium 进程,并发高时机器压力很大。生产化的建议是常驻一个渲染服务复用浏览器实例,或者在容器里做进程池。具体怎么做要看实际架构,但“每次请求拉起一个浏览器”的方案只适合低并发内网工具。
9. Mermaid 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| mmdc 命令找不到 | CLI 未安装或 PATH 未更新 | 执行 npm list -g @mermaid-js/mermaid-cli | 重新全局安装或使用 npx 调用 |
| 首次运行卡在浏览器下载 | Puppeteer 拉取 Chromium 失败 | 查看终端输出中的下载链接和错误码 | 配置镜像或改用系统 Chrome,设置 PUPPETEER_EXECUTABLE_PATH |
| 报错 Cannot find module puppeteer | CLI 依赖未完整安装 | 检查 node_modules 目录 | 删除 node_modules 后重新安装 |
| 图内中文显示为方块 | 字体缺失或 SVG 字体不匹配 | 查看生成的 SVG 中 font-family | 安装中文字体,导出时指定字体配置 |
| 节点文本含括号导致报错 | 特殊字符未转义 | 复制报错信息到 mermaid.live 复现 | 节点文字用双引号包裹,如 A["用户(ID)"] |
| Markdown 预览不渲染 | 插件未加载或代码块语言标签错误 | 检查代码块是否写为 mermaid | 确认代码块标签正确且插件已启用 |
| SVG 背景为透明无法查看 | SVG 默认透明 | 检查使用场景 | 导出时指定 -b white |
| 批量转换中途卡住 | 单个文件语法错误或内存占用高 | 定位卡住的文件,单独执行该文件 | 修复语法,或增加超时和失败重试 |
| 在线链接打不开 | 链接过期或服务不可用 | 重新复制代码生成新链接 | 使用本地 CLI 或自行部署渲染服务 |
这里有两个容易踩的坑值得单独强调。第一个是 npm 网络源不稳定时,mermaid-cli 安装失败概率很高,先把 registry 切到镜像源再安装,能省很多时间。第二个是不要把在线编辑器里写好的敏感图表直接生成共享链接发给别人,内部架构图、数据库表结构、账号体系流程,一律本地渲染后再传播。
10. Mermaid 最佳实践与使用建议
把这些实践沉淀下来,代码化流程图才能真正替代 diagram editor 的工作流,而不是又变成一套没人维护的代码。下面几条是按优先级排的。
先从最小闭环开始。第一次使用先画一张十几节点的流程图,跑通 VS Code 预览、CLI 导出、Git 提交全流程,再决定是否全团队推广。不要一开始就画上千节点的大图,布局不理想后容易怀疑工具不行,实际上是使用姿势问题。
建立目录规范。把 .mmd 源文件按模块或文档分目录存放,比如 diagrams 目录放源文件,docs/assets 放导出图片,让源文件和产物互不混淆。这样批量任务、CI 清理、文档引用都有清晰的路径。
配置统一的导出脚本。把导出命令写进项目的 package.json 或其他脚本文件,避免每次手工敲一长串 mmdc 参数:
{ "scripts": { "diagrams": "mkdir -p docs/assets && for f in diagrams/*.mmd; do mmdc -i \"$f\" -o \"docs/assets/$(basename \"${f%.mmd}\").svg\"; done" } }引入 CI 自动校验。在提交或发布流程中跑一次 mmdc,语法有问题直接构建失败,避免烂图进入正式文档。这一步相当于给流程图加了一个语法检查闸门,效果非常明显。固定 CLI 版本也很重要,锁住 @mermaid-js/mermaid-cli 的版本,避免更新后渲染效果变化导致文档里的图全部换样。
敏感信息处理要养成习惯。涉及架构、账号、客户数据的流程图,先过滤再渲染;对外发布前,检查节点文本是否包含内部域名、IP、密钥片段。自建渲染服务只允许内网访问,接口加请求体大小限制和超时设置,避免被滥用。
11. 总结与下一步
这个项目思路最值得试的点,是把流程图从“画布文件”变成“文本代码”。有了这个前提,版本管理、diff 评审、CI 生成、批量导出全部顺理成章。你维护的是流程逻辑,渲染交给 Mermaid,不再需要回到 diagram editor 里手工重绘。建议先做三件事:在 VS Code 里装好预览插件,把一张现有流程图改用 Mermaid 重写;用 mermaid-cli 跑通一次 SVG/PNG 导出;把导出脚本写进项目,形成固定的文档生成命令。
最容易踩的坑有两个。一是上来就画超大图,布局不理想后觉得工具不行,实际上是没拆图;二是在线服务直接渲染敏感图表,造成信息泄露。这两点规避掉,剩下的就是熟悉语法。后续可以扩展的方向:把 Mermaid 接入接口文档平台,让流程图和接口定义同步更新;用 CI 在每次代码合并后自动刷新架构图;多团队共建公共 .mmd 片段库,复用标准流程子图。先把一条链路跑通,再逐步放大,这套工作流会越用越顺。