首页
/ Mermaid 配置机制详解:defaultConfig、siteConfig 与 Frontmatter 的三层优先级

Mermaid 配置机制详解:defaultConfig、siteConfig 与 Frontmatter 的三层优先级

2026-09-06 17:50:21作者:侯霆垣

本篇技术指南围绕 Mermaid 仓库中的配置文档(configuration.md)展开,系统讲解 Mermaid 启动时的配置来源、siteConfig 的作用域、v10.5.0 引入的 Frontmatter 覆盖机制以及已废弃的 Directive 指令,并结合 config.tsfrontmatter.tsmermaidAPI.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.tsconfig.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 完成——siteConfigcurrentConfig 的初始化均是 assignWithDepth({}, defaultConfig) 产生的独立副本,因此任何上层覆盖都不会污染默认配置。这也是为什么 mermaidAPI.globalReset(见第 6 节)能把配置恢复到出厂状态。

配置的类型定义在 config.type.tsMermaidConfig),各图表(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

  1. 归一化选项:深拷贝 userOptions,并把旧位置的 fontFamily 迁移到 themeVariables.fontFamily(兼容遗留用法);
  2. 保存 initialize 原值configApi.saveConfigFromInitialize(options),用于后续 theme 覆盖时找回 initialize 层级的 themeVariables(见 config.ts#L78-L80);
  3. 主题变量补齐:若 options.theme 是已注册主题,则用 theme[options.theme].getThemeVariables(...) 把主题默认变量与用户传入变量合并;否则回退到 theme.default
  4. 写入 siteConfigconfigApi.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 的修改都会被下一次 addDirectivereset 调用覆盖”(config.ts#L98-L110)。

原文档中的“Theme configuration”一节指向的主题机制(主题与 themeVariables 的合并规则、可用主题清单)在 theming.md 中详述;从 setSiteConfiginitialize 的源码结构看,主题变量遵循“主题默认值 ← 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-yamlJSON_SCHEMA 解析(frontmatter.ts#L42-L47),保证类型安全;
  • 白名单式提取:只保留显式支持的元数据字段 titledisplayMode(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 数组并重新合并。addDirectiveconfig.ts#L173-L186)内部会先执行 sanitizeDirectivesanitize(见第 7 节),并对 fontFamily 做与 initialize 一致的向后兼容迁移,然后:

directives.push(directive);
updateCurrentConfig(siteConfig, directives);

updateCurrentConfigconfig.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 会被最先调用。源码验证了这一生命周期:

export const reset = (config = siteConfig): void => {
  directives = [];                       // 清空上一张图遗留的指令
  updateCurrentConfig(config, directives);
};
  • 调用点(mermaidAPI.ts#L72-L77):processAndSetConfigs 在每次 renderparse 时先执行 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-L166sanitize 函数强制实施,它同时应用于 directive 与 Frontmatter 配置(addDirective 首行调用 sanitizeDirective,合并流程中再次 sanitize)。其规则包括:

  1. secure 键保护secure 本身以及 siteConfig 中 secure 数组列出的键,一旦出现在图表侧配置中即被删除,仅记录 debug 日志。源码特别注释:不得在日志模板字符串中打印被拒值,以免恶意脚本利用 logger 的字符串化过程执行任意代码;
  2. 原型污染防护:删除所有以 __ 开头的键,阻断通过 __proto__ 等键的注入;
  3. XSS 防护:字符串值中包含 <>url(data: 的键值被整体删除——注释说明这是为了防止 base64 data URL 内嵌带内联脚本的 SVG。

此外,config.ts#L246-L252getEffectiveHtmlLabels 展示了配置优先级在单项参数上的落地:htmlLabels 的有效值按“全局 htmlLabels ← 已废弃的 flowchart.htmlLabels ← 默认 true”取用,并对旧键发出弃用警告;类似的弃用检查(如 lazyLoadedDiagrams/loadExternalDiagramsAtStartup 应改用 registerExternalDiagrams)集中在 checkConfigconfig.ts#L217-L225),每次 render config 更新后都会执行。

8. 小结:配置优先级与落地检查清单

综合原文档与源码实现,Mermaid 单张图表的 render config 组装顺序为:

  1. defaultConfig(出厂默认,defaultConfig.ts);
  2. siteConfig(站点 initialize 一次性深合并于其上,mermaidAPI.ts#L663-L690);
  3. 图表作者层:Frontmatter config(v10.5.0+,推荐)或 Directives(已废弃),经 sanitize 安全过滤后 addDirective 合并(config.ts#L173-L186);
  4. 每次渲染前 configApi.reset() 清空上张图的指令,确保隔离(mermaidAPI.ts#L72-L77)。

实践建议:站点级品牌/主题用 initialize 统一配置并只调用一次;单图差异(如临时换 theme、调 themeVariables)用 Frontmatter 表达,避免使用已废弃的 %%{init: ...}%% 指令;涉及 secure 键的配置只应在 siteConfig 层设置,图表侧的覆盖会被 sanitize 静默拒绝;排查配置不生效时,可先用 mermaidAPI.getConfig() 观察当前 render config,再对照 config.spec.tse2e/diagrams/conf-and-directives/ 中的用例定位是覆盖顺序、缩进解析还是安全过滤导致的差异。

登录后查看全文
热门项目推荐
相关项目推荐