Integrating Mermaid JS Into Hugo
Date: 2021-02-20 · Word Count: 397 · Reading Time: 2 minutes
I had originally planned to write up an introduction to StormCrawler, but found myself wanting to draw state diagrams. Hugo doesn’t seem to have Graphviz support builtin, so I started to poke around and see what else was out there.
For those who want pure Graphviz, there’s viz-js. It’s a pretty straight forward implementation, although it hasn’t been updated in a while and the documentation suggests that people should take a look at DagreJS. I did and it didn’t really win me over.
Further poking around suggested that there’s more choice in this space than I’d realised:
There are also services which will render your graphs for you and embed an SVG, such as Gravizo. I really didn’t want anything like that, although I can see how it might be handy for embedding in GitHub wikis.
After a bit of poking around, I ended up choosing to use Mermaid. It has good docs, support for a fairly broad set of graph types and is entirely JavaScript so I can just embed it in my pages.
The Mermaid documentation recommends sourcing from jsdeliver.net. That’s all fine and good, but I like being able to survive outages in other services, so I wanted a fallback to local serving if there was a failure. After reading way too much about working around various old browsers etc, it turns out the answer was quite simple and Stack Overflow lead me to a solution in HTML 5 Boilerplate.
The final gotcha was that .Params is now $.Page.Params in Hugo. Which was rather obscurely pointed to by:
executing "shortcodes/mermaid.html" at <.Params.mermaid>: can't evaluate field mermaid in type interface {}
To create the short code, put the following in layouts/shortcodes/mermaid.html:
{{ if ($.Page.Params.mermaid) }}
<script src="//cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>!window.mermaid && document.write(unescape('%3Cscript src="/js/mermaid-8.9.1/mermaid.min.js"%3E%3C/script%3E'))</script>
<script>mermaid.initialize({startOnLoad:true});</script>
{{ end }}
<div class="mermaid">
{{.Inner}}
</div>
The if block ensures that the JavaScript only loads if mermaid is in use in the page, which you can enable by putting mermaid: true in the parameters at the top of your page.
Then you can produce beautiful graphs by embedding code like this:
---
... Page parameters ...
mermaid: true
---
{{<mermaid>}}
sequenceDiagram
participant John
participant Alice
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
{{</mermaid>}}
To get a graph like this: