yupanzi

Hexo 添加 Mermaid 图表支持

· 3 分钟阅读

想在技术博客中画流程图、时序图?Mermaid 可以让我们用代码直接绘制各种图表,无需额外的绘图工具。

问题背景

Hexo 默认的 Markdown 渲染器会把所有代码块(包括 mermaid)渲染成带行号的 <figure><table> 结构,而 Mermaid.js 只能识别简单的 <pre class="mermaid"> 标签。我们需要一个轻量的解决方案。

实现方案

本文基于 Hexo Frame 主题,但方案也适用于其他主题(需调整对应的配置文件路径)。

采用原生配置 + 脚本转换的方式,无需安装任何 npm 插件

1. 添加主题配置

Frame 主题:编辑 themes/frame/_config.yml

其他主题:编辑对应主题的 _config.yml(如 themes/next/_config.yml

添加 Mermaid 配置:

# mermaid diagram setting
mermaid_enable: true
mermaid_version: "11"  # mermaid 版本

2. 加载 Mermaid.js

Frame 主题:编辑 themes/frame/layout/partials/head.ejs

其他主题:找到主题的 head 模板文件(通常在 layout/_partial/head.ejslayout/partials/head.ejs

</head> 前添加:

<%# mermaid diagram support %>
<% if(theme.mermaid_enable){ %>
    <% var mermaidVersion = theme.mermaid_version || '11'; %>
    <script type="module">
        import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@<%= mermaidVersion %>/dist/mermaid.esm.min.mjs';
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default'
        });
    </script>
<% } %>

3. 添加 HTML 转换脚本

创建 scripts/mermaid-renderer.js通用方案,适用于所有主题):

/**
 * Mermaid renderer for Hexo
 * Converts mermaid code blocks from <figure> to <pre class="mermaid">
 */

hexo.extend.filter.register('after_post_render', function(data) {
  // Only process if mermaid is enabled
  if (!hexo.theme.config.mermaid_enable) {
    return data;
  }

  // Replace <figure class="highlight plaintext"> containing mermaid code
  data.content = data.content.replace(
    /<figure class="highlight plaintext"><table><tr><td class="gutter">[\s\S]*?<\/td><td class="code"><pre>([\s\S]*?)<\/pre><\/td><\/tr><\/table><\/figure>/g,
    function(match, code) {
      // Extract plain text from the code
      const plainCode = code
        .replace(/<span class="line">/g, '')
        .replace(/<\/span>/g, '')
        .replace(/<br>/g, '\n')
        .trim();

      // Check if it looks like mermaid code
      const mermaidKeywords = ['graph', 'sequenceDiagram', 'classDiagram', 'stateDiagram', 'gantt', 'pie', 'flowchart', 'erDiagram', 'journey'];
      const isMermaid = mermaidKeywords.some(keyword => plainCode.startsWith(keyword));

      if (isMermaid) {
        return '<pre class="mermaid">' + plainCode + '</pre>';
      }

      return match;
    }
  );

  return data;
});

使用示例

流程图

graph TD
    A[开始] --> B{需要图表?}
    B -->|是| C[使用 Mermaid]
    B -->|否| D[纯文本描述]
    C --> E[完成]
    D --> E

时序图

sequenceDiagram
    participant 客户端
    participant 服务器
    participant 数据库

    客户端->>服务器: 发起请求
    服务器->>数据库: 查询数据
    数据库-->>服务器: 返回结果
    服务器-->>客户端: 响应数据

甘特图

gantt
    title 项目计划
    dateFormat YYYY-MM-DD
    section 开发
    功能开发    :2025-01-01, 5d
    代码审查    :2025-01-06, 2d
    section 测试
    测试验证    :2025-01-08, 3d

配置说明

配置项说明默认值
mermaid_enable是否启用 Mermaidfalse
mermaid_versionMermaid 版本号"11"

版本配置示例

  • "11" - 使用 11.x 最新版
  • "10.9.0" - 使用指定版本

主题适配说明

本方案由三部分组成:

  1. 主题配置:在主题的 _config.yml 中添加开关和版本配置
  2. 脚本加载:在主题的 head 模板中添加 CDN 脚本(需要适配主题
  3. HTML 转换scripts/mermaid-renderer.js 脚本(通用,无需修改

如果你使用的不是 Frame 主题,只需要调整步骤 1 和步骤 2 的文件路径,步骤 3 的脚本完全通用。

注意事项

  • Hexo 脚本修改后需重启 hexo server
  • Mermaid 代码块会自动识别关键字(graphsequenceDiagram 等)
  • 如需关闭渲染,设置 mermaid_enable: false

更多图表语法参考 Mermaid 官方文档

相关文章