背景

博客之前不支持数学公式渲染,对于技术文章中涉及数学表达式的内容(如算法分析、机器学习公式等)无法正确显示。此外,mermaid 图表引擎版本过旧(v8.8.0),无法支持较新的图表语法。本次更新通过集成 KaTeX 引擎和改进 Mermaid 渲染方式(按 Hugo 官方文档采用 CDN ESM 模块),解决了这两个问题。

技术方案

选择 KaTeX 而非 MathJax,主要考虑以下因素:

  • 渲染速度:KaTeX 的渲染速度比 MathJax 快得多
  • 体积轻量:CDN 加载,不增加项目体积
  • Hugo 原生支持:Hugo 的 Goldmark 扩展支持 passthrough 模式,与 KaTeX 配合良好

改动内容

1. 修改 config.yml

Hugo Goldmark passthrough 扩展配置

markup 部分添加了 passthrough 扩展,让 Hugo 在处理 Markdown 时保留数学公式的原始内容,而不是转义其中的特殊字符:

markup:
  goldmark:
    extensions:
      passthrough:
        delimiters:
          block:
            - - \[
              - \]
            - - $$
              - $$
          inline:
            - - \(
              - \)
            - - $
              - $
        enable: true

全局启用数学公式

params 中添加 math: true,使所有页面默认支持数学公式:

params:
  math: true

2. 修改 layouts/partials/extend_head.html

引入 KaTeX 的 CSS 样式表和 JavaScript 库:

{{ if .Params.math | default .Site.Params.math }}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" crossorigin="anonymous"></script>
{{ end }}

3. 修改 layouts/partials/extend_footer.html

添加 KaTeX auto-render 初始化脚本,在页面 DOM 加载完成后自动渲染数学公式:

{{ if .Params.math | default .Site.Params.math }}
<script>
document.addEventListener("DOMContentLoaded", function () {
    renderMathInElement(document.body, {
        delimiters: [
            { left: "$$", right: "$$", display: true },
            { left: "$", right: "$", display: false },
            { left: "\\[", right: "\\]", display: true },
            { left: "\\(", right: "\\)", display: false }
        ],
        throwOnError: false
    });
});
</script>
{{ end }}

使用方式

行内公式

使用单个 $\(...\) 包裹:

质能方程 $E = mc^2$ 是物理学中著名的公式。

渲染效果:质能方程 $E = mc^2$ 是物理学中著名的公式。

块级公式

使用双 $$\[...\] 包裹:

$$
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$

渲染效果:

$$ \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi} $$

更多示例

矩阵:

$$ \begin{bmatrix} a & b \\ c & d \end{bmatrix} $$

求和公式:

$$ \sum_{i=1}^{n} i = \frac{n(n+1)}{2} $$

欧拉公式:

$$ e^{i\pi} + 1 = 0 $$

薛定谔方程:

$$ i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \hat{H}\Psi(\mathbf{r},t) $$

踩坑记录

在初次部署后发现数学公式无法渲染,排查发现是 KaTeX CDN 资源的 integrity(SRI hash)值写错了,导致浏览器在加载 CSS 和 JS 文件时校验失败,资源被拒绝加载。移除错误的 integrity 属性后问题解决。

教训:使用 CDN 资源时,SRI hash 必须与实际文件内容完全匹配。如果不确定正确的 hash 值,建议不添加 integrity 属性,仅使用 crossorigin="anonymous" 即可。


Mermaid 图表渲染

问题描述

博客中已有的 mermaid.js 版本为 8.8.0,该版本不支持较新的 mermaid 语法(如 flowchart TD、新版 sequenceDiagram 等),导致图表渲染报错 Syntax error in graph mermaid version 8.8.0

改动内容

1. 删除本地 mermaid.min.js,改用 CDN ESM 模块

移除 static/js/mermaid.min.js(原 v8.8.0,约 3MB),改为从 CDN 按需加载 ESM 模块,始终获取最新版本。

2. 创建 layouts/_markup/render-codeblock-mermaid.html

按照 Hugo 官方文档 创建代码块渲染钩子(注意路径是 layouts/_markup/,不是 layouts/_default/_markup/):

<pre class="mermaid">
{{ .Inner | htmlEscape | safeHTML }}
</pre>
{{ .Page.Store.Set "hasMermaid" true }}

Page.Store.Set "hasMermaid" true 标记页面使用了 mermaid 图表。

3. 修改 layouts/_default/baseof.html

</body> 标签前添加 mermaid ESM 脚本,按需加载(只有使用 mermaid 的页面才会加载):

{{ if .Store.Get "hasMermaid" }}
<script type="module">
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
  mermaid.initialize({ startOnLoad: true });
</script>
{{ end }}

4. 清理 extend_head.html

移除 layouts/partials/extend_head.html 中之前添加的 mermaid 加载脚本(不再需要)。

使用方式

直接在文章中使用 mermaid 代码块即可,不需要在 front matter 中设置 mermaid: true

```mermaid
flowchart TD
    A[开始] --> B{条件判断}
    B -->|是| C[操作1]
    B -->|否| D[操作2]
```

Hugo 的 render hook 会自动将代码块转为 <pre class="mermaid"> 元素,baseof.html 中的 ESM 脚本会自动检测并渲染。

更多示例

流程图:

graph TD
    A[输入数据] --> B[预处理]
    B --> C{数据质量?}
    C -->|合格| D[模型训练]
    C -->|不合格| E[数据清洗]
    E --> B
    D --> F[评估]
    F --> G[部署]

序列图:

sequenceDiagram
    participant U as 用户
    participant S as 服务器
    participant D as 数据库
    U->>S: 发送请求
    S->>D: 查询数据
    D-->>S: 返回结果
    S-->>U: 响应

注意事项

数学公式

  • 数学公式使用 KaTeX CDN 加载,需要网络连接
  • KaTeX 支持大部分 LaTeX 数学语法,但不支持所有 LaTeX 宏包
  • 如果某篇文章不需要数学公式,可以在 front matter 中设置 math: false 来禁用,减少不必要的资源加载
  • 行内公式中避免使用 $ 符号作为货币单位,如需使用可用 \$ 转义

Mermaid 图表

  • 在文章 front matter 中设置 mermaid: true 才能加载 mermaid.js
  • 推荐使用 mermaid 代码块语法,也支持 shortcode 方式插入
  • mermaid.js v10.9.3 支持所有主流图表类型:flowchart、sequenceDiagram、classDiagram、stateDiagram、gantt、pie 等
  • mermaid.js 文件较大(约 3MB),仅在需要的文章中加载

参考资料