Skip to content

⬆️ 升级 mermaid 至 11.16.0 并改进图表加载 - #1255

Open
fulequn wants to merge 6 commits into
fluid-dev:developfrom
fulequn:feat/mermaid-11
Open

fulequn wants to merge 6 commits into
fluid-dev:developfrom
fulequn:feat/mermaid-11

Conversation

@fulequn

@fulequn fulequn commented Oct 22, 2026 •

Copy link
Copy Markdown

背景

主题当前锁定的 mermaid 版本是 8.14.0(2021 年),模板里调用的是 mermaid.init()。从 mermaid 10 开始 init() 已被移除,只保留 mermaid.run(),因此不升级就无法跟进新版本,也无法使用新版支持的图表类型。

改动

  1. _config.yml:static_prefix.mermaid 升级到 11.16.0(baomitu 上没有 11.x,改用 jsdelivr);同时重写 post.mermaid.enable 的注释,说明默认会自动检测图表,只有运行时注入(加密插件、动态内容)或未引入 markdown 正文样式的页面才需要 mermaid: true。
  2. layout/_partials/plugins/mermaid.ejs:
    • mermaid.init() → mermaid.run();
    • 固定 startOnLoad: false,统一由 run() 控制渲染时机,避免 mermaid 的自动渲染发生在 initialize() 应用配置之前;
    • 不传 suppressErrors:run() 本身会逐图捕获错误并继续渲染其余图表,最后统一 reject;加上该参数会让 reject 被吞掉,catch 永远收不到错误,失败也失去可观测性;
    • 初始渲染显式调用一次,同时保留 registerRefreshCallback 支持评论/懒加载后的重新渲染;run() 会跳过带 data-processed 的节点,不会重复渲染;
    • 通过新的 onerror 回调,在脚本加载失败时输出 [Fluid] Failed to load mermaid from <url>。
  3. 新增 scripts/utils/mermaid.js(元素级检测):不再对整段 HTML 跑宽松正则,而是剔除注释、<script>/<style>/<template> 后按标签解析 class,按 ASCII 空白拆 token,兼容单引号/双引号/无引号。这样 data-class="mermaid"、title='class="mermaid"'、注释与脚本里的文本不会被误判,class=mermaid、class="mermaid someone's" 也不会漏判。
  4. 检测契约与渲染契约对齐:run({ querySelector: '.mermaid' }) 只认 mermaid token,所以运行时检测同样只认 mermaid;language-mermaid 仅作为 prism 适配器转换前的输入标记(hasMermaidCode)。裸的 <code class="language-mermaid"> 不会被当作图表。
  5. scripts/helpers/mermaid.js:注册 has_mermaid helper,供 layout/_partials/markdown-plugins.ejs 在 EJS 里调用(EJS 中无法 require)。specific: true 时自动检测正文中的图表(```mermaid 代码块、{% mermaid %} 标签、<div class="mermaid">),mermaid: false 可显式关闭。
  6. scripts/events/lib/highlight.js:hljs 行号/非行号分支与 prism 分支的三处宽松判断统一改为 token 级检测,language-not-mermaid、language-mermaid-wrapper 不再被误删高亮或行号;prism 分支用 toMermaidClass 只替换独立的 language-mermaid token。
  7. scripts/events/lib/mermaid.js:构建期在「页面有图表但不会加载脚本」时输出警告,改用同一套元素级检测。
  8. source/js/utils.js:createScript(url, onload, onerror),向后兼容原有两参调用。

测试

test/run.js 分为检测器单元用例与四组真实 Hexo 构建。

检测器单元用例(21 条元素用例 + 4 条类名改写)覆盖:data-class、title='class="mermaid"'、HTML 注释、<template>、<script>/<style> 正文、&lt;div class="mermaid"&gt;、language-mermaid、not-mermaid、mermaid-wrapper 均不触发;复合 class、无引号、单引号、属性值内含 >、多行属性、双引号内含撇号均正确命中;toMermaidClass 只替换独立 token 并保留引号与其它类名。

构建矩阵(固定版本:hexo 8.1.2、hexo-renderer-marked 7.0.1、hexo-prism-plugin 2.3.0 等):

构建 断言
enable: true、specific: true、options: {theme: forest, startOnLoad: true} 9 个页面按预期注入/不注入脚本;options 原样透传且 startOnLoad 被覆盖为 false;无 mermaid.init(;run({querySelector: '.mermaid'}) 形态精确;含加载失败提示
同上但 enable: false 全页面不注入,警告恰好覆盖有真实图表的 5 个页面
hljs + line_number: true mermaid 块解包 figure、去行号;not-mermaid 保留 figure、hljs 类与行号
prism + line_number: true + preprocess: true language-mermaid 改写为 mermaid 且无残留;行号与 pre 属性被清理;not-mermaid 保留 language-not-mermaid 与行号;HTML 围栏里的示例保持高亮文本

同时断言裸 <div class="mermaid"> 不会被包成 code-wrapper、代码围栏里的 mermaid 示例不会变成真实图表。

本地执行:node test/run.js(无网络环境可用 FLUID_TEST_MODULES=<已有 node_modules 路径> 复用依赖)。

验证

  • node test/run.js 全部通过(含自建 npm install 的 CI 路径)。
  • 真实浏览器(mermaid 11.16.0 + headless Chromium):坏图渲染为 mermaid 自身的语法错误占位,同页后续图表正常渲染;不传 suppressErrors 时 run() 会 reject(catch 生效),传了则 resolve——即上面的第 2 条。
  • Hexo 8.1.2 + 本地主题,一篇包含 sequenceDiagram(4 个参与者)的文章:生成 SVG 正常,data-processed 存在,刷新回调不会重复渲染;页面其它依赖(TOC、anchor、fancybox)不受影响。
  • 浏览器控制台无未捕获错误。

兼容性

post.mermaid.options 仍然是原样透传给 mermaid.initialize(),没有做字段改写。v11 的 sequence 配置里 useMaxWidth、width、actorMargin、messageMargin 等键都还在,原有配置不需要迁移;如果用户配置了 v8 独有的键,mermaid 会忽略。行为变化有两处:startOnLoad 会被强制为 false,以保证配置先生效;渲染失败现在会进 console.error 而不是被静默吞掉。

需要提醒的是:默认 CDN 版本变化属于破坏性变更(新版本对个别旧语法更严格),如果维护者倾向保守,也可以只合并渲染逻辑的部分,CDN 版本单独用配置覆盖。

已知限制

  • 构建期警告挂在 after_post_render,与主题其它 lib 一致;Hexo 渲染缓存命中时该过滤器不会重复执行,警告可能不再出现。
  • 裸 <code class="language-mermaid"> 视为不可渲染文本,不加载脚本(与 run() 的选择器保持一致)。
  • 加密插件、运行时注入的图表,以及未包含 markdown-body 的页面,仍需在 Front-matter 指定 mermaid: true。
  • 文档站(fluid.ist)的 mermaid 配置说明需要同步更新。

🤖 Generated with Claude Code

mermaid 10 起移除了 mermaid.init(),原调用在新版本下会直接报错。
改为 mermaid.run(),并捕获渲染异常,避免单个图表语法错误中断整页。
默认 CDN 同步升级到 11.16.0,配置项说明指向新版 schema 文档。

Co-Authored-By: Claude Code <noreply@anthropic.com>
@fulequn fulequn changed the title ⬆️ 升级 mermaid 至 11.16.0 并适配 run 接口 ⬆️ 升级 mermaid 至 11.16.0 并改进图表加载 Oct 22, 2026
fulequn and others added 2 commits October 22, 2026 14:06
- specific 为 true 时自动检测页面内的 mermaid 块,避免忘记写 Front-matter 导致图表退化为纯文本
- 支持通过 `mermaid: false` 显式关闭
- 固定 startOnLoad 为 false,由 mermaid.run 统一渲染,避免自动渲染早于 initialize 生效
- 传入 options 会覆盖 run 的默认 querySelector,需显式指定,否则不会渲染任何图表
- 使用 suppressErrors,单个图表语法错误不再影响同页其他图表
- 构建期在图表存在但不会加载脚本时输出警告

Co-Authored-By: Claude Code <noreply@anthropic.com>
用最小 Hexo 站点验证:Front-matter、正文代码块、{% mermaid %} 标签三种来源
都能正确注入脚本,纯文本页不注入,显式关闭时给出构建警告。

Co-Authored-By: Claude Code <noreply@anthropic.com>
fulequn and others added 2 commits October 23, 2026 11:15
- 新增元素级检测:剔除注释、script/style/template,按标签属性解析 class token,
  修掉 data-class、属性值内的 class="mermaid"、无引号 class 等误报与漏报
- 检测契约与渲染契约对齐:运行时只认 mermaid token,language-mermaid 仅作为
  代码块适配器转换前的标记
- highlight.js 与 prism 适配器改用同一检测,language-not-mermaid、
  language-mermaid-wrapper 不再被误删高亮/行号或改名
- 移除 mermaid.run 的 suppressErrors,使渲染失败能被 catch 观测到;
  补充脚本加载失败的 onerror 提示
- 补充检测器单元用例与四组真实构建测试(开启/关闭/hljs 行号/prism preprocess)

Co-Authored-By: Claude Code <noreply@anthropic.com>
首页自动摘要直接复用 post.content,代码围栏里的 mermaid 图表会以
"graph TD ..." 的形式出现在文章列表和本地搜索里。

新增 strip_mermaid helper:先按 class token 整体移除 mermaid 节点
(pre/code/div,兼容 language-mermaid),再交给 strip_html 取纯文本。
只匹配独立的 mermaid token,mermaid-wrapper 之类的名字不受影响。

Co-Authored-By: Claude Code <noreply@anthropic.com>
- description 先移除 mermaid 与代码块、解码 HTML 实体,再交给 open_graph,
  避免图表源码和 "&amp;" 这类转义原样进入 meta description
- og:image 增加正文首张绝对地址图片,优先级为
  og_img > index_img > 正文首图 > 站点默认图
- 新增 json_ld helper:文章输出 BlogPosting、首页输出 WebSite,
  并转义 "<" 防止正文提前闭合 script 标签

Co-Authored-By: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant