Mermaid @mermaid-js/examples 实战指南:构建、验证与消费官方示例图库
本文围绕 mermaid 仓库中的 packages/examples/README.md 展开,讲解 @mermaid-js/examples 包的定位、数据结构与扩展方式:如何为某个图表类型编写并注册示例图、测试门禁如何保证每条示例都能被正确解析,以及第三方工具(如 mermaid.live)如何消费这个示例库获取每种图表的默认样例。读完本文,你可以独立完成新增一个图表示例、理解示例数据的 id/name/examples 三元结构,并复用官方示例消费逻辑为自己的编辑器或文档站点生成样板代码。
1. 包的定位:示例图不是文档,而是可安装的运行时数据
@mermaid-js/examples 是一个独立的 npm 包,它把 mermaid 支持的各种图表类型的示例源码(flowchart、sequence、C4、gantt、state 等)组织成一份结构化的 TypeScript 数据,供 mermaid.live 等工具在用户新建图表时提供"开箱即用"的起始代码。
从 package.json 可以看到它的关键特征:
- 包名
@mermaid-js/examples,当前版本1.4.0,MIT 协议,"type": "module"的纯 ESM 包; - 入口为编译产物:
"module": "./dist/mermaid-examples.core.mjs",类型声明在./dist/index.d.ts,exports只暴露.一个子路径,即整个包只导出示例数据,没有附带运行时代码依赖(dependencies为空对象); - 唯一的运行时协作对象是
mermaid本身,且仅以"mermaid": "workspace:*"的形式出现在devDependencies中——说明示例包在生产侧是"纯数据",只有在仓库内部做测试时才依赖 mermaid 来校验示例可解析性。
这意味着任何宿主应用引入该包后,拿到的只是一份经过类型约束的元数据数组,渲染职责完全由宿主侧的 mermaid 实例承担。
2. 数据结构:Example 与 DiagramMetadata 两层模型
理解整个包的起点是 types.ts,它定义了只有两个接口:
export interface Example {
title: string;
code: string;
isDefault?: boolean;
}
export interface DiagramMetadata {
id: string;
name: string;
description: string;
examples: Example[];
}
各字段含义与约定如下:
| 字段 | 层级 | 含义与约束 |
|---|---|---|
id |
DiagramMetadata | 与 mermaid 内部注册的图表 id 对应(如 flowchart-v2、c4、usecase),是测试用例做 diagramData.find((d) => d.id === diagram.id) 匹配的键 |
name |
DiagramMetadata | 面向用户的图表名称,如 Flowchart、C4 Diagram |
description |
DiagramMetadata | 一句话描述该图表的用途,宿主可用它生成下拉菜单说明文字 |
title |
Example | 单条示例的展示标题 |
code |
Example | 完整的 mermaid 图表源码字符串,可直接丢给 mermaid.render / mermaid.parse |
isDefault |
Example | 可选布尔值,标记该图表的"默认示例";约定每个图表有且仅有一条为 true |
所有示例文件都以 export default { ... } satisfies DiagramMetadata; 结尾,satisfies 关键字保证在获得类型检查的同时保留字面量推断,任何字段拼写错误都会在建构时直接报错。
3. 中央注册表:index.ts 中的 diagramData 数组
index.ts 是唯一的聚合点。它的模式非常直接:
- 逐文件
import每个图表的默认导出的元数据对象,例如import flowChart from './examples/flowchart.js'、import c4 from './examples/c4.js'; - 将这些对象按顺序平铺进一个导出的
diagramData: DiagramMetadata[]数组。
当前注册表收录了 33 个条目,覆盖 flowchart、c4、ishikawa、kanban、class、sequence、pie、user-journey、mindmap、requirement、radar、state、er、git、architecture、xychart、sankey、gantt、timeline、quadrant-chart、packet、block、treemap、usecase、eventmodeling、venn、tree-view、wardley、cynefin,以及 railroad 的四种变体(通用/EBNF/ABNF/PEG,分别对应 railroad.ts、railroad-ebnf.ts、railroad-abnf.ts、railroad-peg.ts)。
README 中给出的扩展流程(packages/examples/README.md)对应到源码就是两步:
- 复制并修改示例文件:以 flowchart.ts 为模板,新建
packages/examples/src/examples/<你的图表>.ts,按DiagramMetadata结构填写; - 在 index.ts 中注册:添加一行 import,并把对象追加进
diagramData数组。
README 同时强调了内容策略:"每种图表至少应有一条示例,且必须标记为默认(isDefault: true);建议再添加更多示例以展示该图表的不同特性。" 以 flowchart 为例,flowchart.ts 实际提供了 4 条示例,逐层递进地展示能力面:
export default {
id: 'flowchart-v2',
name: 'Flowchart',
description: 'Visualize flowcharts and directed graphs',
examples: [
{
title: 'Basic Flowchart',
isDefault: true,
code: `flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]`,
},
{
title: 'Online Checkout Flow',
code: `flowchart TD
Start([Visit online store]) --> Browse[Browse products]
...
style Start fill:#e8f5e9,stroke:#43a047`,
},
// 还有 'CI/CD Pipeline with Subgraphs'(子图与跨子图连线)、
// 'Expanded Node Shapes'(@{ shape: ... } 扩展节点形状)等
],
} satisfies DiagramMetadata;
这个分层写法值得借鉴:第一条默认示例保持最小、稳定(便于宿主做"新建图表"占位);后续示例则分别演示 style 指令、subgraph 跨图连线、@{ shape: docs, ... } 等进阶语法,形成一份内嵌的能力展示目录。c4.ts 同样遵循该模式,默认示例是完整的 Internet Banking C4Context(含 Enterprise_Boundary 嵌套、Person / System_Ext / SystemQueue 等节点类型与 BiRel/Rel 关系),第二条则换成 C4Container 视角。
4. 质量门禁:测试如何保证示例库"永远可渲染"
示例库最大的风险是"文档腐化"——mermaid 语法演进后示例悄悄失效。example.spec.ts 用三层测试封死了这个风险:
- 覆盖性检查:调用
mermaid.getRegisteredDiagramsMetadata()取出运行时注册的全部图表,剔除明确的跳过列表(error、info等无示例图表,以及被 v2 版本覆盖的旧 id 如graph、flowchart、class),断言每个注册图表都能在diagramData中找到同id的条目、示例数大于 0,且data.examples.filter((e) => e.isDefault).length恰好为 1——即"每种图表必须有示例、且默认示例唯一"是硬约束; - 全量可解析性检查:遍历
diagramData中每一条example.code,断言mermaid.parse(example.code)成功。任何一条示例语法写坏,对应测试会以Example "<title>" of <id> does not parse明确指向责任条目; - 抽样真实渲染检查:对 usecase 的每条示例额外执行
mermaid.render,断言产物中存在<svg>且包含[data-usecase-kind]节点,验证的不只是"能解析",还是"能渲染出预期结构"。
测试还做了环境适配:mock SVGElement.prototype.getBBox / getComputedTextLength 以支持无头浏览器环境下的渲染测量。从源码结构看,这套门禁意味着上游 PR 只要改动示例语法,就会在 CI 中被精确到"哪条示例的哪个标题"级别的报错拦截。
5. 宿主侧消费:mermaid.live 的用法
安装与最小用法在 README 中给出:
pnpm add @mermaid-js/examples
下面是 README 提供的、源自 mermaid.live 的完整消费示例:为每种图表类型取回其默认示例代码,并按"去掉 Diagram/Chart/Graph 后缀"的规则生成 Record<string, string> 映射:
import { diagramData } from '@mermaid-js/examples';
type DiagramDefinition = (typeof diagramData)[number];
const isValidDiagram = (diagram: DiagramDefinition): diagram is Required<DiagramDefinition> => {
return Boolean(diagram.name && diagram.examples && diagram.examples.length > 0);
};
export const getSampleDiagrams = () => {
const diagrams = diagramData
.filter((d) => isValidDiagram(d))
.map(({ examples, ...rest }) => ({
...rest,
example: examples?.filter(({ isDefault }) => isDefault)[0],
}));
const examples: Record<string, string> = {};
for (const diagram of diagrams) {
examples[diagram.name.replace(/ (Diagram|Chart|Graph)/, '')] = diagram.example.code;
}
return examples;
};
这段代码里有三个值得注意的工程细节:
isValidDiagram用类型谓词把"可能不完整"的条目过滤掉,后续代码无需再写空值判断;.map(({ examples, ...rest }) => ...)通过解构把examples数组摘除,只保留选中的默认示例,控制下发到前端的数据体积;- 键名规范化
diagram.name.replace(/ (Diagram|Chart|Graph)/, '')把 "C4 Diagram"、"Quadrant Chart"、"Git Graph" 之类的不统一命名收敛为 "C4"、"Quadrant"、"Git",这是把展示层name转回机器可读键的实用技巧。
如果你的宿主应用需要的是"完整示例列表"而非仅默认示例(例如构建文档站、图表选型页),直接遍历 diagramData 的 examples 数组即可,title 用作展示名、code 填入编辑器、isDefault 决定初始高亮。
6. 适用前提与限制
- 该包只发布
dist产物("files": ["dist"]),消费方拿到的是编译后的.mjs与.d.ts,示例源码本身在 src/examples/ 目录下,需要修改示例时应回到源码仓库提交 PR,而非本地改写 dist; diagramData的id必须与 mermaid 当前版本的图表注册 id 对齐(如 flowchart 的 id 是flowchart-v2而非graph)。从 CHANGELOG.md 可以看到,每当 mermaid 新增图表类型(Ishikawa、TreeView 等),examples 包都会跟随发布一个 minor 版本补齐示例,这是两个包版本联动的原因;- 1.3.0 / 1.4.0 两个版本的重点是"为每种图表补充贴近真实场景、突出该图表强项的示例",因此示例内容本身在持续演化,消费方不应把具体
code字符串当作长期不变的常量缓存,建议每次依赖升级后重新生成样板数据。
7. 小结:扩展一个图表示例的完整清单
结合 README 与源码,新增一个图表示例的完整流程可以归纳为:
- 复制 flowchart.ts 为
packages/examples/src/examples/<name>.ts,按DiagramMetadata结构填写id(与 mermaid 注册 id 一致)、name、description与至少一条isDefault: true的示例; - 在 index.ts 中添加 import 并追加进
diagramData数组; - 依赖 example.spec.ts 的三层门禁自动验证:id 覆盖、默认示例唯一、全部示例可解析(必要时补充渲染级断言);
- 宿主侧通过
pnpm add @mermaid-js/examples引入,按第 5 节的getSampleDiagrams模式取数即可。
这样,示例库既是用户的"入门样板",也是 mermaid 各图表语法的活体回归测试集——数据只有一份,文档、编辑器与测试共享同一来源。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00