EN

KO

Integrating Mermaid.js in Zola

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.

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!