首页
/ Mermaid 配置机制深读:getEffectiveHtmlLabels 如何裁决 htmlLabels 标签渲染开关

Mermaid 配置机制深读:getEffectiveHtmlLabels 如何裁决 htmlLabels 标签渲染开关

2026-09-06 17:02:51作者:庞眉杨Will

getEffectiveHtmlLabels 是 Mermaid 配置层中一个看似不起眼、却横跨整个渲染管线的关键辅助函数。它负责在「根级全局配置」「已废弃的图表级配置」与「默认值」之间裁决出最终生效的 htmlLabels 布尔值,并顺带发出弃用警告。读懂它,不仅能理解 Mermaid 中「节点/边标签到底用 HTML 还是纯 SVG 文本渲染」这一行为的决定机制,还能掌握 Mermaid 配置合并(default → initialize → directive)与弃用迁移设计的完整套路。本文以该函数为轴心,结合 config.ts 源码、config.spec.ts 测试与渲染层调用点,逐层展开。

函数签名与文档定位

官方 API 文档页 getEffectiveHtmlLabels.md(由 Typedoc 自动生成,源文件在 packages/mermaid/src/docs/config/setup/config/functions/getEffectiveHtmlLabels.md)对该函数的定义非常精炼:

getEffectiveHtmlLabels(config): boolean

Helper function to handle deprecated flowchart.htmlLabels

Defined in: packages/mermaid/src/config.ts:246

  • 参数 config: MermaidConfig — The configuration object (merged config with defaults)
  • 返回 boolean — The effective htmlLabels value based on precedence: root > flowchart > default

三点信息值得抓住:

  1. 输入是「合并后的配置」——即已经过 defaultConfig 与用户配置深合并的对象,而不是原始用户输入;
  2. 返回值是布尔量,语义上等价于「本次渲染是否启用 HTML 标签」;
  3. 优先级链:根级 htmlLabels > 图表级 flowchart.htmlLabels(已废弃)> 默认值 true

源码实现逐行拆解

函数本体位于 packages/mermaid/src/config.ts#L241-L252

/**
 * Helper function to handle deprecated flowchart.htmlLabels
 * @param config - The configuration object (merged config with defaults)
 * @returns The effective htmlLabels value based on precedence: root flowchart  default
 */
export const getEffectiveHtmlLabels = (config: MermaidConfig): boolean => {
  // != instead of !== handles null case
  if (config.flowchart?.htmlLabels != undefined) {
    issueWarning('FLOWCHART_HTML_LABELS_DEPRECATED');
  }
  return evaluate(config.htmlLabels ?? config.flowchart?.htmlLabels ?? true);
};

三个实现细节各有讲究:

1. 用 != 而非 !== 判断「用户是否显式设置了 flowchart.htmlLabels」

config.flowchart?.htmlLabels != undefined 是宽松比较,能同时捕获 nullundefined。这意味着:只要合并后的配置里 flowchart.htmlLabels 不是 undefined——哪怕值是 null——都会触发弃用警告。注释中 // != instead of !== handles null case 明确了这一意图。

警告文案定义在 packages/mermaid/src/config.ts#L200-L205

const ConfigWarning = {
  LAZY_LOAD_DEPRECATED:
    'The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead.',
  FLOWCHART_HTML_LABELS_DEPRECATED:
    'flowchart.htmlLabels is deprecated. Please use global htmlLabels instead.',
} as const;

2. 警告只发一次:issuedWarnings 去重机制

packages/mermaid/src/config.ts#L207-L215 实现了一个模块级单发警告器:

type ConfigWarningStrings = keyof typeof ConfigWarning;
const issuedWarnings: Partial<Record<ConfigWarningStrings, boolean>> = {};
const issueWarning = (warning: ConfigWarningStrings) => {
  if (issuedWarnings[warning]) {
    return;
  }
  log.warn(ConfigWarning[warning]);
  issuedWarnings[warning] = true;
};

getEffectiveHtmlLabels 在渲染管线中被高频调用(每个节点标签、每条边标签都可能触发一次),如果没有去重,控制台会被同一条弃用警告刷屏。issuedWarnings 用键值记录「该警告是否已发过」,保证整个进程生命周期内 flowchart.htmlLabels is deprecated... 只出现一次。

3. 用 evaluate 把「字符串型布尔」归一化

最终返回值经过 packages/mermaid/src/config.ts#L16-L17evaluate 函数:

export const evaluate = (val?: string | boolean | null): boolean =>
  val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true;

它把 false'false''null''0'(忽略大小写与首尾空白)都归一为 false,其余一切(包括 true'true''1'、空值)归一为 true。这样处理的原因在于:配置值可能来自 mermaid.initialize 的 JS 对象,也可能来自 HTML 属性或配置文件中以字符串形式传入的布尔值,evaluate 保证了取值语义的一致性。

完整优先级链

把上面三处组合起来,决策过程为:

步骤 表达式 语义
① 弃用探测 config.flowchart?.htmlLabels != undefined 图表级值存在(含 null)→ 发一次弃用警告,但不影响取值
② 取值 config.htmlLabels ?? config.flowchart?.htmlLabels ?? true 根级优先;其次是(已废弃的)flowchart 级;两者皆无则回退 true
③ 归一 evaluate(...) 字符串/布尔 → 标准布尔

注意步骤②使用的是 ??(空值合并),null 同样会触发回退——即 htmlLabels: null 不占位,会继续看下一级。这与步骤①中刻意用宽松比较探测 null 形成对照:警告按「存在即警告」,取值按「空即回退」。

类型定义中的弃用标记

packages/mermaid/src/config.type.ts#L158-L166 对根级 htmlLabels 的 JSDoc 明确记录了迁移规则:

/**
 * Flag for setting whether or not a html tag should be used for rendering labels on nodes and edges.
 * **Note:** Diagram-specific `htmlLabels` settings (e.g., `flowchart.htmlLabels`) are deprecated.
 * Use this root-level `htmlLabels` setting instead. The root-level `htmlLabels` takes precedence
 * over any diagram-specific settings.
 */
htmlLabels?: boolean;

而 flowchart 配置块内的同名属性在 packages/mermaid/src/config.type.ts#L302-L310 被标注为:

/**
 * @deprecated
 * **DEPRECATED: Use global `htmlLabels` instead.**
 * Flag for setting whether or not a html tag should be used for rendering labels on nodes and edges.
 * This property is deprecated.
 * Please use the global `htmlLabels` configuration instead.
 */
htmlLabels?: boolean | null;

类型签名上 boolean | null 的写法(允许 null)正是与实现中「null 也触发警告」相对应的。另外 packages/mermaid/src/config.type.ts#L860 附近还保留了 classDiagram 自己的 htmlLabels?: boolean 字段,但 getEffectiveHtmlLabels 的裁决链只涉及根级与 flowchart 级两处。

测试用例:优先级矩阵全覆盖

packages/mermaid/src/config.spec.ts#L302-L369describe('getEffectiveHtmlLabels', ...) 用 8 个用例覆盖了完整的优先级与指令(directive)场景,是理解该函数行为的最佳权威依据:

场景 输入 期望
根级 true setSiteConfig({ htmlLabels: true }) true
根级 false setSiteConfig({ htmlLabels: false }) false
仅 flowchart true(根级未设) { flowchart: { htmlLabels: true } } true
仅 flowchart false(根级未设) { flowchart: { htmlLabels: false } } false
冲突时根级胜出 htmlLabels: false + flowchart.htmlLabels: true false
两者都未设 setSiteConfig({}) true(默认值回退)
directive 设置 flowchart.htmlLabels=false 站点默认 + addDirective({ flowchart: { htmlLabels: false } }) false
directive 设根级 htmlLabels 压过站点 flowchart 值 站点 flowchart.htmlLabels: true + addDirective({ htmlLabels: false }) false
directive 根级 true 压过站点 flowchart false 站点 flowchart.htmlLabels: false + addDirective({ htmlLabels: true }) true

后三个用例揭示了它与 Mermaid 指令体系的联动:mermaid 代码块内的 %%{init: ...}%% 指令会通过 packages/mermaid/src/config.ts#L173-L186addDirective 进入 updateCurrentConfig,与 siteConfigassignWithDepth 深合并后才成为 getConfig() 返回的对象——也就是 getEffectiveHtmlLabels 拿到的输入。因此「directive 覆盖站点配置」本质上发生在配置合并阶段,函数本身只做纯函数式的裁决。

渲染管线中的消费点:谁在调用它

getEffectiveHtmlLabels 并非孤立存在,它是渲染层判断「用 HTML 标签还是 SVG 文本」的统一入口。从源码调用面看,主要消费点包括:

一个值得注意的模式是 node.useHtmlLabels ?? getEffectiveHtmlLabels(getConfig())(见 collapsedGroup.ts#L60util.ts#L126):节点级 useHtmlLabels 提供第三层细粒度覆盖,而 getEffectiveHtmlLabels 始终是它的全局兜底。

除了直接渲染,还有两个「跨领域」的消费点:

1. classDef 样式生成。 packages/mermaid/src/mermaidAPI.ts#L153-L156 中,getEffectiveHtmlLabels(config) 决定了 classDef 的 CSS 选择器策略:启用 HTML 标签时 CSS 作用于 ['> *', 'span'](DOM 元素),否则作用于 ['rect', 'polygon', 'ellipse', 'circle', 'path'](SVG 形状元素)。这就是为什么同一份 classDef 在两种模式下要生成两套选择器。

2. 文本安全清洗。 packages/mermaid/src/diagrams/common/common.ts#L70-L83sanitizeMore 直接以 getEffectiveHtmlLabels(config) 为闸门:

const sanitizeMore = (text: string, config: MermaidConfig) => {
  if (getEffectiveHtmlLabels(config)) {
    const level = config.securityLevel;
    if (level === 'antiscript' || level === 'strict' || level === 'sandbox') {
      text = removeScript(text);
    } else if (level !== 'loose') {
      text = breakToPlaceholder(text);
      text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
      text = text.replace(/=/g, '&equals;');
      text = placeholderToBreak(text);
    }
  }
  return text;
};

即:只有当 HTML 标签模式生效时,才按 securityLevel 决定用 DOMPurify 移除脚本(removeScript,见同文件 L62-L68)还是做实体转义。这意味着 htmlLabels 的取值不仅影响外观,还参与安全策略的分叉——修改该开关时要同时理解它对 XSS 防护路径的影响。

配置实践:如何正确设置与迁移

推荐写法:使用根级 htmlLabels

无论通过 mermaid.initialize 还是代码块内的 directive,迁移后的规范写法是把开关提到根级:

<script>
  mermaid.initialize({
    startOnLoad: true,
    htmlLabels: false, // 全局禁用 HTML 标签(所有图表类型统一生效)
  });
</script>
%%{init: {"htmlLabels": false}}%%
flowchart LR
  A[普通文本标签] --> B

config.type.ts 的 JSDoc 与 config.spec.ts 的「冲突时根级胜出」用例可确认:一旦设置了根级 htmlLabels,任何图表级旧配置都被忽略。

旧写法仍然可用,但会收到一次警告

<script>
  mermaid.initialize({
    startOnLoad: true,
    flowchart: { htmlLabels: false }, // 已废弃:控制台会输出
    // "flowchart.htmlLabels is deprecated. Please use global htmlLabels instead."
  });
</script>

行为上完全等价于旧语义(测试用例 3、4 保证向后兼容),代价是控制台出现一条弃用警告——且如前所述,该警告每个进程只出现一次。

默认行为

两者都不设时,config.ts#L251?? true 兜底使 htmlLabels 默认为启用,这与「HTML 标签可支持富文本、换行与图片」的默认产品行为一致;config.spec.ts 中「should default to true when neither root nor flowchart htmlLabels is explicitly set」用例对此做了锁定。

字符串值的坑

由于 evaluate'false''null''0' 都解析为 false,通过字符串渠道(如模板字符串拼接配置)传值时要留意引号形式;而 'yes''1'true 之外的任意值都会落到 true 分支。

小结与延伸阅读

getEffectiveHtmlLabels 浓缩了 Mermaid 配置系统的三个典型设计:深合并后统一裁决(default → initialize → directive 分层在 updateCurrentConfig 中完成,函数只读合并结果)、弃用而非删除flowchart.htmlLabels 保留取值能力、叠加单发警告)、归一化输入evaluate 兼容字符串型布尔)。它同时是渲染管线中 HTML 标签模式的唯一裁决入口,下游覆盖了节点/边/子图标题的度量、classDef CSS 选择器策略与 securityLevel 下的文本清洗分叉。

继续深入可参考:

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