Astro 集成 Mermaid:解决 Shiki 高亮导致的渲染失效

Astro 集成 Mermaid:解决 Shiki 高亮导致的渲染失效


Astro
Astro Mermaid

表现

在 Astro 项目中配置 Mermaid 客户端渲染时,常遇到一种情况:脚本加载正常且无报错,但页面上的代码块依然显示为纯文本,无法转化为图表。 image.png

根本原因

Mermaid 官方脚本默认寻找类名为 .mermaid 的节点进行转换。然而,Astro 默认集成的 Shiki 高亮引擎在处理 Markdown 时,会生成一层自定义的外壳。

其真实的 DOM 结构类似于: <pre class="astro-code..." data-language="mermaid">

由于节点上没有 .mermaid 类名,原生的 Mermaid 初始化逻辑直接脱靶,导致渲染流程在寻址阶段就中断了。

2. 解决方案

既然 Shiki 的结构不可控,我们就改用属性选择器 data-language="mermaid" 锁定节点。在脚本中手动提取纯文本代码,并销毁 Shiki 渲染的原始节点,替换为 Mermaid 能识别的标准容器。

3. 最终可执行脚本

在全局布局文件(如 src/layouts/BaseLayout.astro)的 </body> 闭合标签上方注入以下代码。这里使用了 is:inline 指令,确保脚本绕过 Astro 的本地打包流程。

<script type="module" is:inline>
  // 1. 初始化,禁用自动加载
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
  mermaid.initialize({ startOnLoad: false, theme: 'default' });

  // 2. 锁定 Shiki 生成的特定 pre 节点
  const mermaidNodes = document.querySelectorAll('pre[data-language="mermaid"]');
  
  if (mermaidNodes.length > 0) {
    mermaidNodes.forEach((preNode) => {
      // 提取代码块内的纯文本逻辑
      const codeNode = preNode.querySelector('code');
      const rawCode = codeNode ? codeNode.textContent : preNode.textContent;
      
      // 动态创建标准的 Mermaid 渲染容器
      const div = document.createElement('div');
      div.className = 'mermaid';
      div.style.display = 'flex';
      div.style.justifyContent = 'center';
      div.style.margin = '2rem 0';
      div.textContent = rawCode;
      
      // 用新生成的 div 物理替换原始的 pre 节点
      preNode.replaceWith(div);
    });
    
    // 3. 手动触发渲染引擎
    mermaid.run();
  }
</script>

这种处理方式避开了繁琐的高亮配置修改,直接在 DOM 层解决了 Shiki 与 Mermaid 的渲染冲突问题。

修复后:

image.png

© 2026 Personal Website
Developed by Ryan 🫡