Hugo 内容中的图表(Diagrams):GoAT 内建渲染与 Mermaid 自定义渲染钩子完整指南
【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo
本文围绕 docs/content/en/content-management/diagrams.md 展开,系统讲解在 Hugo 站点内容中嵌入图表的两种主流方案:由 Hugo 内建支持的 GoAT(纯 ASCII 图表,开箱即用、零依赖、生成 SVG)与通过 Markdown 代码块渲染钩子(code block render hook)接入的 Mermaid(时序图、流程图等复杂图表)。读完本文,你将掌握 goat 围栏代码块的属性用法、diagrams.Goat模板函数的底层原理、Mermaid 渲染钩子与按需加载脚本的完整落地配置,并可直接套用 7 类经典 GoAT 示例(图形、复杂图、流程、文件树、时序、流程图、表格)。
GoAT 图表(ASCII):开箱即用的内建能力
GoAT(Go ASCII Tool)是一种用纯文本字符绘制图表的标记语言。Hugo 通过内嵌的代码块渲染钩子(embedded code block render hook)原生支持 GoAT,无需任何配置即可使用,这也是它与 Mermaid 的最大区别——Mermaid 需要用户自行编写渲染钩子,而 GoAT 是内置模板。
工作原理
从源码结构看,Hugo 将 GoAT 能力封装在 tpl/diagrams/goat.go 中,通过模板函数diagrams.Goat对外暴露。该函数接收任意输入(io.Reader、[]byte或字符串),统一交给 GoAT 库的goat.BuildSVG生成 SVG 数据,再包装为SVGDiagram对象返回:
Inner():仅返回 SVG 内部子元素(不含<svg>包裹),便于自定义包装;Wrapped():返回带<svg>包裹的完整片段;Width()/Height():返回渲染后图表的像素宽高。
对应的内嵌渲染钩子模板位于 tpl/tplimpl/embedded/templates/_markup/render-codeblock-goat.html,其输出结构为:
<div class="goat svg-container {{ $class }}"> <svg xmlns="http://www.w3.org/2000/svg" font-family="Menlo,Lucida Console,monospace" viewBox="0 0 {{ width }} {{ height }}"> ...SVG 内部元素... </svg> </div>模板会读取代码块 info 字符串中的通用属性(Attributes):width、height、class。当指定了width或height时使用固定的width/height属性;未指定时则使用viewBox按比例自适应缩放,字体族固定为等宽字体Menlo, Lucida Console, monospace,保证字符对齐精度。
基础用法:从 Markdown 到 SVG
在内容文件的围栏代码块中使用goat作为语言标识即可。例如,以下 Markdown:
```goat . . . .--- 1 .-- 1 / 1 / \ | | .---+ .-+ + / \ .---+---. .--+--. | '--- 2 | '-- 2 / \ 2 + + | | | | ---+ ---+ + / \ / \ .-+-. .-+-. .+. .+. | .--- 3 | .-- 3 \ / 3 / \ / \ | | | | | | | | '---+ '-+ + 1 2 3 4 1 2 3 4 1 2 3 4 '--- 4 '-- 4 \ 4 ```将被渲染为:
. . . .--- 1 .-- 1 / 1 / \ | | .---+ .-+ + / \ .---+---. .--+--. | '--- 2 | '-- 2 / \ 2 + + | | | | ---+ ---+ + / \ / \ .-+-. .-+-. .+. .+. | .--- 3 | .-- 3 \ / 3 / \ / \ | | | | | | | | '---+ '-+ + 1 2 3 4 1 2 3 4 1 2 3 4 '--- 4 '-- 4 \ 4Hugo 构建时即把该文本转换为内联 SVG,浏览器端无需任何 JavaScript。集成测试 markup/goldmark/codeblocks/codeblocks_integration_test.go 中验证了这一链路:测试先自定义了layouts/_markup/render-codeblock-goat.html来调用diagrams.Goat .Inner,再断言最终输出包含<svg class='diagram' xmlns='http://www.w3.org/2000/svg' ...>结构,并且width="600"属性被正确传递。
属性与自定义渲染钩子
GoAT 代码块支持在 info 字符串中携带通用属性,例如:
```goat {width="300" color="orange"} ───Linux─┬─Android ├─Debian─┬─Ubuntu─┬─Lubuntu └─Fedora ```这里的width会作用于渲染钩子中的<svg>标签,class会追加到div.goat.svg-container的 class 列表中,方便你用 CSS 定制样式。
如需深度定制输出(例如包装成<figure>、加题注、改字体),可以创建自己的layouts/_markup/render-codeblock-goat.html覆盖内嵌模板,参考 docs/content/en/functions/diagrams/Goat.md 中的示例:
{{ $caption := or .Attributes.caption "" }} {{ $class := or .Attributes.class "diagram" }} {{ $id := or .Attributes.id (printf "diagram-%d" (add 1 .Ordinal)) }} <figure id="{{ $id }}"> {{ with diagrams.Goat (trim .Inner "\n\r") }} <svg class="{{ $class }}" width="{{ .Width }}" height="{{ .Height }}" xmlns="http://www.w3.org/2000/svg" version="1.1"> {{ .Inner }} </svg> {{ end }} <figcaption>{{ $caption }}</figcaption> </figure>需要注意,代码块渲染钩子的 context 是固定的,参见 docs/content/en/render-hooks/code-blocks.md:Type(语言标识,即goat)、Inner(围栏内文本)、Attributes(通用属性 map)、Options(高亮选项)、Ordinal(页面内代码块的零基序号)、Page(当前页面引用)等。这正是上述示例中Attributes.caption、Ordinal的取值来源。
在模板解析层面,tpl/tplimpl/templatestore.go 对渲染钩子的匹配做了专门处理(代码注释即提到render-codeblock-goat.html):当用户提供了自定义渲染钩子模板时,用户模板优先于内嵌模板;只有用户未覆盖时才使用内嵌版本。内嵌模板的注册关系记录在 docs/data/embedded_template_urls.toml 中('render-codeblock-goat' = '_markup/render-codeblock-goat.html'),GoAT 渲染依赖 go.mod 中声明的github.com/bep/goat v0.5.0模块。
Mermaid 图表:用代码块渲染钩子按需接入
与 GoAT 不同,Hugo不提供Mermaid 的内建模板。Mermaid 的渲染依赖浏览器端的 JavaScript 库,因此需要两步:先把 Markdown 中的mermaid代码块转换为特定 HTML 结构,再在页面加载 Mermaid 脚本完成渲染。
第一步:创建 Mermaid 渲染钩子
在layouts/_markup/下新建render-codeblock-mermaid.html:
<pre class="mermaid"> {{ .Inner | htmlEscape | safeHTML }} </pre> {{ .Page.Store.Set "hasMermaid" true }}这段模板做了两件事:
- 将代码块内容输出为
<pre class="mermaid">。由于 Mermaid 源码中可能包含<、>、&等字符,先用htmlEscape转义再由safeHTML放行,避免破坏 HTML 结构; - 通过
Page.Store.Set在当前页面的存储中打上hasMermaid标记,供基础模板判断是否按需引入 Mermaid 脚本。
第二步:在基础模板中按需加载脚本
将以下片段放在layouts/baseof.html的底部、</body>标签之前:
{{ 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 }}Store.Get "hasMermaid"与渲染钩子中的Set配对使用,实现按需加载:只有页面中确实出现了mermaid代码块时,才引入 CDN 脚本并初始化,避免全站无谓的脚本开销。注意mermaid.initialize({ startOnLoad: true })会让 Mermaid 自动扫描并渲染所有class="mermaid"的元素。
第三步:在内容中使用
完成上述两步后,即可在 Markdown 中直接使用mermaid语言:
渲染流程为:构建时 Hugo 的 goldmark 渲染器命中render-codeblock-mermaid.html,输出<pre class="mermaid">并标记hasMermaid;页面加载后 Mermaid 脚本自动把其内容绘制为 SVG 图表。同理,你也可以为mermaid之外的语言(如python)创建同名渲染钩子实现语言级定制,目录结构参见 docs/content/en/render-hooks/code-blocks.md。
七类经典 GoAT 示例库
以下示例覆盖了 GoAT 语法的主要形态,均可直接复制到内容中使用,部分示例来源于 Diagon 工具(一个可视化的 ASCII 图表生成器,便于快速生成这类文本标记)。
图形(Graphics)
三维立方体与坐标系示意图:
. 0 3 P * Eye / ^ / *-------* +y \ +) \ / Reflection 1 /| 2 /| ^ \ \ \ v *-------* | | v0 \ v3 --------*-------- | |4 | |7 | *----\-----* | *-----|-* +-----> +x / v X \ .-.<-------- o |/ |/ / / o \ | / | Refraction / \ *-------* v / \ +-' / \ 5 6 +z v1 *------------------* v2 | o-----o v复杂图(Complex)
多种形状组合的复杂示意图,包含圆角框、对角线、曲线箭头、if (a > b)条件判断等元素,是验证 GoAT 表现力的典型样例:
+-------------------+ ^ .---. | A Box |__.--.__ __.--> | .-. | | | | '--' v | * |<--- | | +-------------------+ '-' | | Round *---(-. | .-----------------. .-------. .----------. .-------. | | | | Mixed Rounded | | | / Diagonals \ | | | | | | | & Square Corners | '--. .--' / \ |---+---| '-)-' .--------. '--+------------+-' .--. | '-------+--------' | | | | / Search / | | | | '---. | '-------' | '-+------' |<---------->| | | | v Interior | ^ ' <---' '----' .-----------. ---. .--- v | .------------------. Diag line | .-------. +---. \ / . | | if (a > b) +---. .--->| | | | | Curved line \ / / \ | | obj->fcn() | \ / | '-------' |<--' + / \ | '------------------' '--' '--+--------' .--. .--. | .-. +Done?+-' .---+-----. | ^ |\ | | /| .--+ | | \ / | | | Join \|/ | | Curved | \| |/ | | \ | \ / | | +----> o --o-- '-' Vertical '--' '--' '-- '--' + .---. <--+---+-----' | /|\ | | 3 | v not:line 'quotes' .-' '---' .-. .---+--------. / A || B *bold* | ^ | | | Not a dot | <---+---<-- A dash--is not a line v | '-' '---------+--' / Nor/is this. ---流程(Process)
开始/结束、输入、判断、复杂处理、预备等节点的完整流程图:
. .---------. / \ | START | / \ .-+-------+-. ___________ '----+----' .-------. A / \ B | |COMPLEX| | / \ .-. | | END |<-----+CHOICE +----->| | | +--->+ PREPARATION +--->| X | v '-------' \ / | |PROCESS| | \___________/ '-' .---------. \ / '-+---+---+-' / INPUT / \ / '-----+---' ' | ^ v | .-----------. .-----+-----. .-. | PROCESS +---------------->| PROCESS |<------+ X | '-----------' '-----------' '-'文件树(File tree)
利用{width=300 color="orange"}属性展示 Linux 发行版目录树。该示例由 Diagon 的 Tree 功能生成:
───Linux─┬─Android ├─Debian─┬─Ubuntu─┬─Lubuntu │ │ ├─Kubuntu │ │ ├─Xubuntu │ │ └─Xubuntu │ └─Mint ├─Centos └─Fedora时序图(Sequence diagram)
通过{class="w-40"}附加响应式宽度类,展示 Alice 与 Bob 之间的消息交互。该示例由 Diagon 的 Sequence 功能生成:
┌─────┐ ┌───┐ │Alice│ │Bob│ └──┬──┘ └─┬─┘ │ │ │ Hello Bob! │ │───────────>│ │ │ │Hello Alice!│ │<───────────│ ┌──┴──┐ ┌─┴─┐ │Alice│ │Bob│ └─────┘ └───┘流程图(Flowchart)
经典的“你懂流程图吗”问答式幽默流程图,演示了圆角/直角框、yes/no 分支与多级嵌套判断的写法。该示例由 Diagon 的 Flowchart 功能生成:
_________________ ╱ ╲ ┌─────┐ ╱ DO YOU UNDERSTAND ╲____________________________________________________│GOOD!│ ╲ FLOW CHARTS? ╱yes └──┬──┘ ╲_________________╱ │ │no │ _________▽_________ ______________________ │ ╱ ╲ ╱ ╲ ┌────┐ │ ╱ OKAY, YOU SEE THE ╲________________╱ ... AND YOU CAN SEE ╲___│GOOD│ │ ╲ LINE LABELED 'YES'? ╱yes ╲ THE ONES LABELED 'NO'? ╱yes└──┬─┘ │ ╲___________________╱ ╲______________________╱ │ │ │no │no │ │ ________▽_________ _________▽__________ │ │ ╱ ╲ ┌───────────┐ ╱ ╲ │ │ ╱ BUT YOU SEE THE ╲___│WAIT, WHAT?│ ╱ BUT YOU JUST ╲___ │ │ ╲ ONES LABELED 'NO'? ╱yes└───────────┘ ╲ FOLLOWED THEM TWICE? ╱yes│ │ │ ╲__________________╱ ╲____________________╱ │ │ │ │no │no │ │ │ ┌───▽───┐ │ │ │ │ │LISTEN.│ └───────┬───────┘ │ │ └───┬───┘ ┌──────▽─────┐ │ │ ┌─────▽────┐ │(THAT WASN'T│ │ │ │I HATE YOU│ │A QUESTION) │ │ │ └──────────┘ └──────┬─────┘ │ │ ┌────▽───┐ │ │ │SCREW IT│ │ │ └────┬───┘ │ │ └─────┬─────┘ │ │ │ └─────┬─────┘ ┌───────▽──────┐ │LET'S GO DRING│ └───────┬──────┘ ┌─────────▽─────────┐ │HEY, I SHOULD TRY │ │INSTALLING FREEBSD!│ └───────────────────┘表格(Table)
利用{class="w-80 dark-blue"}属性呈现文法的 EBNF 语法定义表格。该示例由 Diagon 的 Table 功能生成:
┌────────────────────────────────────────────────┐ │ │ ├────────────────────────────────────────────────┤ │SYNTAX = { PRODUCTION } . │ ├────────────────────────────────────────────────┤ │PRODUCTION = IDENTIFIER "=" EXPRESSION "." . │ ├────────────────────────────────────────────────┤ │EXPRESSION = TERM { "|" TERM } . │ ├────────────────────────────────────────────────┤ │TERM = FACTOR { FACTOR } . │ ├────────────────────────────────────────────────┤ │FACTOR = IDENTIFIER │ ├────────────────────────────────────────────────┤ │ | LITERAL │ ├────────────────────────────────────────────────┤ │ | "[" EXPRESSION "]" │ ├────────────────────────────────────────────────┤ │ | "(" EXPRESSION ")" │ ├────────────────────────────────────────────────┤ │ | "{" EXPRESSION "}" . │ ├────────────────────────────────────────────────┤ │IDENTIFIER = letter { letter } . │ ├────────────────────────────────────────────────┤ │LITERAL = """" character { character } """" .│ └────────────────────────────────────────────────┘两种方案如何选型
结合本文的实现细节,可归纳出以下选型建议:
| 维度 | GoAT(内建) | Mermaid(渲染钩子) |
|---|---|---|
| 配置成本 | 零配置,内嵌渲染钩子 | 需自建render-codeblock-mermaid.html+ base 模板脚本 |
| 渲染时机 | 构建期静态生成 SVG | 浏览器端加载 JS 后渲染 |
| 依赖 | 无外部依赖(内嵌于 Hugo) | CDN 加载 mermaid.esm.min.mjs |
| 图表类型 | 框图、流程图、时序、文件树、表格等 ASCII 图形 | 时序图、甘特图、状态机、思维导图等丰富的 Mermaid 方言 |
| 自定义能力 | 可覆盖渲染钩子,diagrams.Goat提供Inner/Wrapped/Width/Height | 可扩展任意 Mermaid 语法 |
如果图表相对规整、希望构建产物零 JS 依赖,优先选择 GoAT;如果需求涉及甘特图、状态图等复杂模型,或希望利用 Mermaid 生态的交互能力,则按本文三步接入 Mermaid。两种方案可以共存于同一站点——渲染钩子按语言标识精确匹配,互不干扰。
进一步阅读:代码块渲染钩子的通用机制详见 docs/content/en/render-hooks/code-blocks.md;diagrams.Goat模板函数的方法签名与自定义示例详见 docs/content/en/functions/diagrams/Goat.md;GoAT 渲染实现可查看 tpl/diagrams/goat.go 与内嵌模板 tpl/tplimpl/embedded/templates/_markup/render-codeblock-goat.html。
【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考