preloader

Search Here

When Mermaid Diagrams Break in Production: Debugging Hugo + Azure + Cloudflare Hosting


In this article:

blog-image

Mermaid is a powerful tool for visualizing architecture diagrams in Markdown using simple syntax. If you’re using Hugo as your static site generator and deploying to Azure Static Web Apps with Cloudflare as a CDN, you might hit an unexpected snag:

✅ Diagrams render perfectly during development with hugo serve ❌ Diagrams disappear completely in production

That was exactly the issue I encountered recently — and here’s what I learned, how I debugged it, and how to solve it.


The Setup

  • Static site: Hugo
  • Hosting: Azure Storage Account with Static Website feature
  • CDN / Domain / Caching: Cloudflare
  • Diagram engine: Mermaid, loaded via CDN with type=“module”

Example Mermaid loader snippet:

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

The Problem

The Mermaid diagrams rendered beautifully when testing locally with:

hugo serve

But after deploying to production, all diagrams silently failed to load — no errors, no visuals.

✅ Mermaid script was included

✅ Hugo render hooks were working

✅ No 404s or network errors

❌ But… no rendered graphs


Root Cause: Cloudflare’s Rocket Loader

After verifying that Hugo output and Azure blob MIME types were correct, the issue turned out to be Cloudflare’s Rocket Loader feature.

Rocket Loader rewrites and defers JavaScript on your pages to improve performance – but it breaks ES module loading (type=“module”) by modifying the script loading behavior.

⚠️ Rocket Loader

Rocket Loader assumes traditional JS scripts and doesn’t fully support modern module-based imports like ESM.


✅ The Fix: Disable Rocket Loader

1️⃣ Log into your Cloudflare dashboard

2️⃣ Go to your domain → Speed → Optimization

3️⃣ Scroll down to Rocket Loader

4️⃣ Set to OFF

5️⃣ Purge Cache

🎉 After that, Mermaid diagrams began rendering instantly in production — just like in development.


Bonus Tips (in case it’s not Rocket Loader)

If disabling Rocket Loader doesn’t fix it, also check:

1. MIME Types for .mjs

Azure Static Web Apps may not serve .mjs files with the correct application/javascript MIME type. Fix via Azure CLI:

az storage blob service-properties update \
  --account-name <yourStorageAccountName> \
  --static-website \
  --index-document index.html \
  --404-document 404.html \
  --add-content-types "extension=.mjs,mimeType=application/javascript"

2. Fallback to UMD Script

To avoid type=“module” issues entirely, use the classic Mermaid UMD version:

<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
  mermaid.initialize({ startOnLoad: true });
</script>

This works without worrying about ESM compatibility or MIME types.


Lessons Learned

  • hugo serve doesn’t reflect full production behavior — always test your public/ folder in a real static environment.
  • Cloudflare’s optimization tools are powerful but can introduce subtle compatibility bugs.
  • Simple HTML <script> behavior is not always as simple under modern CDNs.

TL;DR

SymptomFix
Mermaid works locally, not in prodDisable Rocket Loader in Cloudflare
.mjs MIME issues in AzureSet correct MIME type via Azure CLI
Module scripts silently failUse classic <script> (non-module) version

Thank you!

signature

--------------------

Follow me:

Share this post among others: