想在技术博客中画流程图、时序图?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 配置:

1
2
3
# 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> 前添加:

1
2
3
4
5
6
7
8
9
10
11
<%# 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通用方案,适用于所有主题):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 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 是否启用 Mermaid false
mermaid_version Mermaid 版本号 "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 官方文档