mermaid updateSiteConfig() 站点级配置 API:合并语义、实现细节与 setSiteConfig 的对比
本篇聚焦 mermaid 配置体系中的 updateSiteConfig() API:它负责在不重置 siteConfig 的前提下,把新的配置增量深合并(deep merge)进站点级配置,并同步刷新当前生效配置。读完本文,你将理解它在 defaultConfig → siteConfig → directives → currentConfig 配置层级中的位置、它与 setSiteConfig() 的关键区别、深合并的底层实现(assignWithDepth),以及它在 run() 渲染主流程中的实际调用场景,能够正确地在应用初始化或动态调参时使用这一 API。
函数签名与来源
根据 API 参考文档 updateSiteConfig.md,该函数的签名为:
updateSiteConfig(conf: MermaidConfig): MermaidConfig
- 参数:
conf,类型为 MermaidConfig,即本次要合并进siteConfig的配置对象。 - 返回值:
MermaidConfig,即合并完成后的最新siteConfig。 - 定义位置:packages/mermaid/src/config.ts(第 82 行)。
该文档为自动生成的 API 参考(文首注明 "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT"),因此本文结合源码对其行为做完整展开。
配置层级:defaultConfig、siteConfig 与 currentConfig
要理解 updateSiteConfig(),先看 config.ts 顶部的模块级状态:
export const defaultConfig: MermaidConfig = Object.freeze(config); // 全局默认配置,被冻结
let siteConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
let configFromInitialize: MermaidConfig;
let directives: MermaidConfig[] = [];
let currentConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
mermaid 维护着一套分层配置:
| 层级 | 变量 | 生命周期 | 说明 |
|---|---|---|---|
| 默认配置 | defaultConfig |
永久 | 冻结(Object.freeze)的出厂默认值,不可变 |
| 站点配置 | siteConfig |
跨渲染持久 | 面向"整站/整应用"的配置基线,reset() 会把 currentConfig 还原到它 |
| 指令配置 | directives |
每次 parse/render 解析出的 YAML frontmatter |
图表内声明的覆盖项 |
| 当前配置 | currentConfig |
每次更新重算 | siteConfig 与 directives 合并、并应用主题变量后的最终生效值 |
siteConfig 的定位在同目录的 setSiteConfig 文档 中有明确说明:"The siteConfig is a protected configuration for repeat use. Calls to reset() will reset the currentConfig to siteConfig." 也就是说,siteConfig 是"受保护的、可重复使用"的配置基线——updateSiteConfig() 正是用来维护这个基线的增量更新入口。
实现走读:深合并 + 重算 currentConfig
updateSiteConfig() 的完整实现非常精炼(config.ts 第 82–87 行):
export const updateSiteConfig = (conf: MermaidConfig): MermaidConfig => {
siteConfig = assignWithDepth(siteConfig, conf);
updateCurrentConfig(siteConfig, directives);
return siteConfig;
};
三步拆解:
assignWithDepth(siteConfig, conf):把入参conf深合并进现有的siteConfig(而非整体替换)。这是它与setSiteConfig()最本质的区别。updateCurrentConfig(siteConfig, directives):以新的siteConfig为底,叠加当前积累的directives,重算currentConfig。从 updateCurrentConfig 的实现 看,它会依次:深拷贝siteConfig→ 逐个sanitize后合并所有 directives → 若涉及theme字段,则通过theme[cfg.theme].getThemeVariables(...)把主题变量(themeVariables)解析成具体值 → 写入currentConfig并执行checkConfig校验。- 返回新的
siteConfig,调用方可直接拿到合并结果。
与之对比,setSiteConfig 的实现是:
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
siteConfig = assignWithDepth({}, defaultConfig); // 从 defaultConfig 全新起步
siteConfig = assignWithDepth(siteConfig, conf); // 再合入 conf
...
};
两者对比清晰:
setSiteConfig(conf):defaultConfig + conf,丢弃此前 siteConfig 中已有的其他增量,属于"整体重建";updateSiteConfig(conf):现有 siteConfig + conf,保留原有增量,只叠加/覆盖 conf 中出现的键,属于"增量更新"。
深合并语义:assignWithDepth 如何工作
assignWithDepth 定义在 packages/mermaid/src/assignWithDepth.ts,是对 Object.assign 的扩展,支持任意深度对象合并,并有两条对配置合并很关键的行为:
undefined目标键自动初始化:若目标对象缺少某键,会自动初始化为{}(或[])后再递归合并,而不是直接抛错或跳过。- 异构类型不相互覆盖(non-clobber):当
dst中某键是对象、而src中同键是字符串/数字等原始值时,保留 dst 的原值。文件头部的 JSDoc 给出了官方示例:
const config_0 = { foo: { bar: 'bar' }, bar: 'foo' };
const config_1 = { foo: 'foo', bar: 'bar' };
const result = assignWithDepth(config_0, config_1);
//-> result: { foo: { bar: 'bar' }, bar: 'bar' }
// 若用传统 Object.assign,config_0 的 foo 会被 config_1 的 'foo' 覆盖
对 updateSiteConfig() 的实际含义:传入 { theme: 'dark' } 只会覆盖主题名,themeVariables、flowchart 等既有嵌套配置原样保留;但传入一个与既有对象键同名的原始值不会把那个对象打平,这是与 Object.assign 语义的重要差异,调参时需要留意。
主流程调用点:run() 中的 startOnLoad 同步
updateSiteConfig() 并不只是留给外部手动调用的 API,mermaid 自身渲染主流程就会使用它。在 packages/mermaid/src/mermaid.ts 的 runThrowsErrors(run() 的内部实现)中:
if (conf?.startOnLoad !== undefined) {
log.debug('Start On Load: ' + conf?.startOnLoad);
mermaidAPI.updateSiteConfig({ startOnLoad: conf?.startOnLoad });
}
即在每次 run() 处理页面上的 .mermaid 节点前,若当前配置里显式声明了 startOnLoad,就通过 updateSiteConfig 把它持久化进 siteConfig,使该选项在后续的 reset() 往返中不会丢失。这体现了 updateSiteConfig 的"增量持久化"定位:只把关心的少数键同步进站点基线,而不触碰其余配置。
API 暴露方式
该函数通过内部冻结对象 mermaidAPI 暴露(packages/mermaid/src/mermaidAPI.ts):
export const mermaidAPI = Object.freeze({
render,
parse,
initialize,
getConfig: configApi.getConfig,
getSiteConfig: configApi.getSiteConfig,
updateSiteConfig: configApi.updateSiteConfig,
reset: () => { configApi.reset(); },
globalReset: () => { configApi.reset(configApi.defaultConfig); },
defaultConfig: configApi.defaultConfig,
});
配合 getSiteConfig(config.ts 第 94–96 行,返回 siteConfig 的深拷贝)和 reset(),一个典型的使用模式是:
import mermaid from 'mermaid';
// 1) 以增量方式更新站点级配置(保留既有 siteConfig 中其他增量)
mermaid.mermaidAPI.updateSiteConfig({ startOnLoad: true, theme: 'dark' });
// 2) 查看更新后的 siteConfig 基线
const site = mermaid.mermaidAPI.getSiteConfig();
// 3) 需要时重置 currentConfig 回到 siteConfig 基线
mermaid.mermaidAPI.reset();
测试用例对合并语义的验证
单元测试直接验证了 updateSiteConfig 的"保留既有键、追加新键"行为。在 packages/mermaid/src/mermaidAPI.spec.ts 的 "copies an object into the configuration" 用例中:
const object = { test1: 1, test2: false };
mermaidAPI.initialize({ testObject: object });
// 增量更新:只传入新键 test3
mermaidAPI.updateSiteConfig({ testObject: { test3: true } });
const config = mermaidAPI.getConfig();
expect(config.testObject.test1).toBe(1); // 既有键保留
expect(config.testObject.test2).toBe(false); // 既有键保留
expect(config.testObject.test3).toBe(true); // 新键被合并进来
这组断言与 assignWithDepth 的深合并语义一一对应:updateSiteConfig 只覆盖入参中显式出现的键,testObject 下未提及的 test1、test2 均原样保留。同一测试文件中(第 653–664 行)的 "resets mermaid config to global defaults" 用例则验证了 initialize + setConfig + reset 的往返语义,可结合理解 siteConfig 作为重置基线的角色。
小结与注意事项
updateSiteConfig(conf)是增量深合并siteConfig并立即重算currentConfig的 API,返回合并后的siteConfig;setSiteConfig 则是基于defaultConfig的整体重建。需要保留既有站点增量时用前者。- 合并由
assignWithDepth驱动,注意其"异构类型不覆盖"的特殊语义,避免误以为原始值能覆盖对象。 siteConfig是reset()的还原目标(见 reset 文档),因此通过updateSiteConfig写入的配置在reset()后依然保留,属于"应用级持久"配置;而directives(图表内 frontmatter)属于单次解析的临时覆盖。- 该 API 在
run()主流程中被用于持久化startOnLoad(mermaid.ts),印证了它"小范围增量同步"的设计定位。 - 本文所述行为均基于当前仓库源码验证,适用前提是仓库当前版本的
packages/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 StartedRust0627
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