Mermaid 配置机制详解:defaultConfig、siteConfig 与 Frontmatter 的三层优先级
本篇技术指南围绕 Mermaid 仓库中的配置文档(configuration.md)展开,系统讲解 Mermaid 启动时的配置来源、siteConfig 的作用域、v10.5.0 引入的 Frontmatter 覆盖机制以及已废弃的 Directive 指令,并结合 config.ts、frontmatter.ts 与 mermaidAPI.ts 的源码实现,说明“渲染配置(render config)”是如何逐层合并、重置与安全检查后应用于每一张图的。读完后你将能够:正确区分四种配置来源的优先级、在站点集成中用 initialize 设置全局配置、在图表代码中用 Frontmatter 安全地覆盖局部参数,并理解每次渲染前 configApi.reset 的底层调用链。
1. 配置来源总览:三层覆盖与 render config
Mermaid 启动时会对配置进行“抽取(extraction)”,以确定某张图最终使用的配置。根据原文档,配置共有如下来源:
- 默认配置(The default configuration):库内置的出厂配置;
- 站点级覆盖(siteConfig):由集成方(网站/应用)通过
initialize调用设置,应用于该站点/应用内的所有图表; - Frontmatter(v10.5.0+):图表作者可以在图表文本顶部的 YAML Frontmatter 中更新选定的配置参数,作用于渲染配置(render config);
- Directives(已被 Frontmatter 取代,标记为 Deprecated):图表作者曾可直接在图表代码中通过指令更新配置参数,同样作用于渲染配置。
原文档对最终生效配置的定义是:The render config——即上述各层配置应用(合并)之后、真正用于渲染的配置。这一“render config”概念在源码中对应 config.ts 里的模块级状态:
let siteConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
let configFromInitialize: MermaidConfig;
let directives: MermaidConfig[] = [];
let currentConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
其中 currentConfig 就是 render config 的载体,而 directives 是一个数组——这说明 directive(含 Frontmatter 解析出的 config,见下文)是“可叠加”的,后加入的条目会覆盖先加入的条目。
四种来源的优先级与归属可整理为:
| 配置来源 | 由谁设置 | 作用范围 | 源码位置 |
|---|---|---|---|
| defaultConfig | Mermaid 维护者 | 所有站点与图表的基底 | defaultConfig.ts、config.ts#L8 |
| siteConfig | 站点集成方(initialize) |
该站点/应用的所有图表 | config.ts#L64-L76 |
| Frontmatter / Directives | 图表作者 | 单张图表的 render config | mermaidAPI.ts#L72-L77 |
checkConfig 校验 |
库内部 | 渲染前发出弃用警告 | config.ts#L217-L225 |
2. 默认配置 defaultConfig
默认配置在 defaultConfig.ts 中定义,并在 config.ts#L8 中被冻结导出:
export const defaultConfig: MermaidConfig = Object.freeze(config);
Object.freeze 只冻结了顶层对象,但 Mermaid 的所有配置合并都通过深度克隆/合并函数 assignWithDepth 完成——siteConfig、currentConfig 的初始化均是 assignWithDepth({}, defaultConfig) 产生的独立副本,因此任何上层覆盖都不会污染默认配置。这也是为什么 mermaidAPI.globalReset(见第 6 节)能把配置恢复到出厂状态。
配置的类型定义在 config.type.ts(MermaidConfig),各图表(flowchart、sequence、gantt 等)的可选参数则以 setup/ 系列文档形式随源码一起存放于 packages/mermaid/src/docs/config/ 目录下,可结合 theming.md 查阅主题相关参数。
3. 站点级配置:mermaid.initialize 只调用一次
原文档给出了 Mermaid 的启动时序,展示了集成方与 Mermaid 之间的交互:
sequenceDiagram
Site->>mermaid: initialize
Site->>mermaid: content loaded
mermaid->>mermaidAPI: init
文档强调:initialize 调用仅被应用一次(applied only once),它由站点集成方调用,用于在站点级别覆盖默认配置。对外入口是 mermaid.ts#L222 中的 initialize:
const initialize = function (config: MermaidConfig) {
mermaidAPI.initialize(config);
};
真正的初始化逻辑在 mermaidAPI.ts#L663-L690:
- 归一化选项:深拷贝
userOptions,并把旧位置的fontFamily迁移到themeVariables.fontFamily(兼容遗留用法); - 保存 initialize 原值:
configApi.saveConfigFromInitialize(options),用于后续 theme 覆盖时找回 initialize 层级的themeVariables(见 config.ts#L78-L80); - 主题变量补齐:若
options.theme是已注册主题,则用theme[options.theme].getThemeVariables(...)把主题默认变量与用户传入变量合并;否则回退到theme.default; - 写入 siteConfig:
configApi.setSiteConfig(options)。
setSiteConfig 的实现(config.ts#L64-L76)体现了 siteConfig 的构造规则——以 defaultConfig 为底、站点配置深合并于其上,同时再次处理 theme -> themeVariables 的合并:
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
siteConfig = assignWithDepth({}, defaultConfig);
siteConfig = assignWithDepth(siteConfig, conf);
if (conf.theme && theme[conf.theme]) {
siteConfig.themeVariables = theme[conf.theme].getThemeVariables(conf.themeVariables);
}
updateCurrentConfig(siteConfig, directives);
return siteConfig;
};
站点集成方的典型用法(配置主题与主题变量):
import mermaid from 'mermaid';
mermaid.initialize({
startOnLoad: false,
theme: 'base',
themeVariables: {
primaryColor: '#00ff00',
},
});
除 initialize 外,mermaidAPI 还暴露了一组站点级配置 API(mermaidAPI.ts#L718-L738):
getConfig:返回当前 render config 的深拷贝(config.ts#L120-L122);getSiteConfig/updateSiteConfig:读取或增量更新 siteConfig(config.ts#L82-L96);reset/globalReset:分别重置到 siteConfig 与 defaultConfig;setConfig:已废弃,源码注释明确说明“任何对 currentConfig 的修改都会被下一次addDirective或reset调用覆盖”(config.ts#L98-L110)。
原文档中的“Theme configuration”一节指向的主题机制(主题与 themeVariables 的合并规则、可用主题清单)在 theming.md 中详述;从 setSiteConfig 与 initialize 的源码结构看,主题变量遵循“主题默认值 ← initialize 值 ← 图表级覆盖”的逐层深合并策略。
4. Frontmatter 配置(v10.5.0+)
原文档给出的 Frontmatter 用法是:图表作者可以在图表顶部的 YAML 块中覆盖除 secure 配置外的整个 Mermaid 配置。官方示例:
---
title: Hello Title
config:
theme: base
themeVariables:
primaryColor: "#00ff00"
---
flowchart
Hello --> World
4.1 解析实现:extractFrontMatter
Frontmatter 的解析在 frontmatter.ts 中完成,关键行为如下:
- 用
frontMatterRegex(定义于 diagram-api/regexes.ts)匹配文本开头的 YAML 块; - 自动去缩进(dedent):捕获 YAML 块的公共缩进并逐行剥离——因为 js-yaml 拒绝以 Tab 缩进的文档,这对粘贴进 IDE/表格中的缩进图表尤其重要;
- 使用
js-yaml的JSON_SCHEMA解析(frontmatter.ts#L42-L47),保证类型安全; - 白名单式提取:只保留显式支持的元数据字段
title、displayMode(gantt 紧凑模式)与config,其余字段被丢弃; - 返回值中的
text是去掉 Frontmatter 后的图表正文,供后续解析器使用。
4.2 从 Frontmatter 到 render config 的调用链
Frontmatter 并不是独立的配置通道——在实现上,它最终汇入与 directive 相同的 addDirective 机制。入口是 mermaidAPI.ts#L72-L77:
function processAndSetConfigs(text: string) {
const processed = preprocessDiagram(text);
configApi.reset();
configApi.addDirective(processed.config ?? {});
return processed;
}
即:先 reset() 把 render config 复位到 siteConfig,再把解析出的 config 作为一条 directive 推入 directives 数组并重新合并。addDirective(config.ts#L173-L186)内部会先执行 sanitizeDirective 与 sanitize(见第 7 节),并对 fontFamily 做与 initialize 一致的向后兼容迁移,然后:
directives.push(directive);
updateCurrentConfig(siteConfig, directives);
updateCurrentConfig(config.ts#L24-L53)就是“render config”的最终装配过程:以 siteConfig 为底 → 逐条深合并 directives → 若 directive 指定了已知主题,则用 initialize 保存的 themeVariables 为基底重新计算主题变量。
在 render/parse 之外的路径上,Diagram.fromText 也会读取 configApi.getConfig() 用于图表类型检测与初始化,因此 Frontmatter 中的配置对解析阶段同样生效。
端到端测试用例位于 e2e/diagrams/conf-and-directives/,例如 should-render-if-values-are-not-quoted-properly.mmd 验证了 Frontmatter 值未正确加引号时的行为,settings-from-frontmatter-nodes-should-be-grey.mmd 则验证站点 initialize(绿色)与 Frontmatter(灰色)设置的合并结果。
5. Directive 指令(已废弃)
原文档将 Directives 标注为“Deprecated by Frontmatter”:图表作者曾可以直接在图表代码里通过 %%{...}%% 指令覆盖配置参数,作用于 render config。这一机制的完整语法(init 指令、theme 指令等)及其与 Frontmatter 的迁移对照,见仓库内的 directives.md。
从源码结构看,Directives 与 Frontmatter 共用同一存储:config.ts 中的 directives: MermaidConfig[] 数组。Directives 路径下指令由图表解析器在解析过程中调用 configApi.addDirective 写入;Frontmatter 路径下则由 processAndSetConfigs 统一写入。两者合并后按“后写覆盖先写”生效(config.ts#L30-L37)。对于新图表,官方推荐一律使用 Frontmatter 表达配置。
6. configApi.reset:每次渲染前复位
原文档对 configApi.reset 的说明是:该方法把某张图的配置复位到站点配置(即站点集成方提供的配置);在每张图渲染之前,reset 会被最先调用。源码验证了这一生命周期:
- 定义(config.ts#L194-L198):
export const reset = (config = siteConfig): void => {
directives = []; // 清空上一张图遗留的指令
updateCurrentConfig(config, directives);
};
- 调用点(mermaidAPI.ts#L72-L77):
processAndSetConfigs在每次render与parse时先执行configApi.reset(),随后才应用本图的 Frontmatter 配置。这保证了图表作者无法通过前一张图的 Frontmatter 污染后一张图——每次渲染的 render config 都从 siteConfig 重新出发。 - 对应的公开 API:
mermaidAPI.reset()等价于configApi.reset(),mermaidAPI.globalReset()则显式传入configApi.defaultConfig复位到出厂配置(mermaidAPI.ts#L731-L736)。
7. 配置安全过滤:secure 键与 sanitize
原文档提到 Frontmatter 可覆盖“除 secure configs 外”的整个配置。这一约束由 config.ts#L131-L166 的 sanitize 函数强制实施,它同时应用于 directive 与 Frontmatter 配置(addDirective 首行调用 sanitizeDirective,合并流程中再次 sanitize)。其规则包括:
- secure 键保护:
secure本身以及 siteConfig 中secure数组列出的键,一旦出现在图表侧配置中即被删除,仅记录 debug 日志。源码特别注释:不得在日志模板字符串中打印被拒值,以免恶意脚本利用 logger 的字符串化过程执行任意代码; - 原型污染防护:删除所有以
__开头的键,阻断通过__proto__等键的注入; - XSS 防护:字符串值中包含
<、>或url(data:的键值被整体删除——注释说明这是为了防止 base64 data URL 内嵌带内联脚本的 SVG。
此外,config.ts#L246-L252 的 getEffectiveHtmlLabels 展示了配置优先级在单项参数上的落地:htmlLabels 的有效值按“全局 htmlLabels ← 已废弃的 flowchart.htmlLabels ← 默认 true”取用,并对旧键发出弃用警告;类似的弃用检查(如 lazyLoadedDiagrams/loadExternalDiagramsAtStartup 应改用 registerExternalDiagrams)集中在 checkConfig(config.ts#L217-L225),每次 render config 更新后都会执行。
8. 小结:配置优先级与落地检查清单
综合原文档与源码实现,Mermaid 单张图表的 render config 组装顺序为:
defaultConfig(出厂默认,defaultConfig.ts);siteConfig(站点initialize一次性深合并于其上,mermaidAPI.ts#L663-L690);- 图表作者层:Frontmatter
config(v10.5.0+,推荐)或 Directives(已废弃),经sanitize安全过滤后addDirective合并(config.ts#L173-L186); - 每次渲染前
configApi.reset()清空上张图的指令,确保隔离(mermaidAPI.ts#L72-L77)。
实践建议:站点级品牌/主题用 initialize 统一配置并只调用一次;单图差异(如临时换 theme、调 themeVariables)用 Frontmatter 表达,避免使用已废弃的 %%{init: ...}%% 指令;涉及 secure 键的配置只应在 siteConfig 层设置,图表侧的覆盖会被 sanitize 静默拒绝;排查配置不生效时,可先用 mermaidAPI.getConfig() 观察当前 render config,再对照 config.spec.ts 与 e2e/diagrams/conf-and-directives/ 中的用例定位是覆盖顺序、缩进解析还是安全过滤导致的差异。
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