Mermaid.js is a powerful library that lets you create various diagrams using Markdown-like syntax. In this post, I'll walk you through the steps to integrate Mermaid.js into a Zola static site generator and how to optimize its performance.
quadrantChart
title Reach and engagement of campaigns
x-axis Low Reach --> High Reach
y-axis Low Engagement --> High Engagement
quadrant-1 We should expand
quadrant-2 Need to promote
quadrant-3 Re-evaluate
quadrant-4 May be improved
Campaign A: [0.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
quadrantChart title Reach and engagement of campaigns x-axis Low Reach --> High Reach y-axis Low Engagement --> High Engagement quadrant-1 We should expand quadrant-2 Need to promote quadrant-3 Re-evaluate quadrant-4 May be improved Campaign A: [0.3, 0.6] Campaign B: [0.45, 0.23] Campaign C: [0.57, 0.69] Campaign D: [0.78, 0.34] Campaign E: [0.40, 0.34] Campaign F: [0.35, 0.78]
1. Creating a Shortcode
The first step to using Mermaid.js in Zola is to create a shortcode. I created mermaid.html in the templates/shortcodes directory.
<pre class="mermaid">
{{ body }}
</pre>
This shortcode is very simple; it just generates a <pre>
tag with the mermaid class. However, Mermaid.js identifies this mermaid class to convert the content into a graph, making it incredibly easy to create diagrams.
2. Adding the Mermaid.js Library
CDN Approach (Initial Method)
Initially, I used a CDN to load Mermaid.js. I added the code to load mermaid.js in my overall layout, base.html
:
<!-- mermaid -->
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true, theme: 'dark' });
</script>
This method was simple to implement but came with the downsides of external dependency and potential network latency.
Internalizing with Local Files (Optimization)
To improve performance and remove external dependencies, I internalized Mermaid.js by saving it as a local file.
First, I found that .mjs files were difficult to handle as they often load multiple chunks. So, I opted to download the .js
file instead.
curl -s https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js -o static/js/mermaid.min.js
Afterward, I loaded it in base.html by referencing the local path:
<!-- mermaid -->
<script src="/js/mermaid.min.js"></script>
<script>
mermaid.initialize({ startOnLoad: false, theme: 'dark' });
</script>
3. Optimizing the Rendering Method
startOnLoad Method (Initial Method)
Initially, I used Mermaid.js's default rendering method, startOnLoad: true
.
mermaid.initialize({ startOnLoad: true, theme: 'dark' });
While this method automatically rendered all diagrams upon page load, it caused a delay in rendering because it waited for all other elements, like images, to fully load on the page.
Manual Rendering Method (Optimization)
I realized it would be better to proceed immediately once the Mermaid code was fully loaded. So, I switched to manually specifying the rendering time. I set startOnLoad: false
to prevent automatic rendering and then changed it to manually render only the necessary elements after the DOM was loaded.
mermaid.initialize({ startOnLoad: false, theme: 'dark' });
document.addEventListener('DOMContentLoaded', async () => {
const mermaidElements = document.querySelectorAll('.mermaid');
if (mermaidElements.length > 0) {
await mermaid.run({
nodes: mermaidElements
});
}
});
As a result, as soon as objects with the mermaid class are identified, rendering starts almost simultaneously with page access.
Conclusion
Let's test with a simple example to see if it works well
mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectiveness<br/>and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid
It works perfectly!