---
title: "Hugo : gel des diagrammes Mermaid en SVG statiques dark/light"
description: "Comment et pourquoi remplacer le rendu Mermaid côté client par des SVG statiques générés au build : paires dark/light via mmdc, hash de contenu, déduplication multilingue, et le piège \u0026nbsp; dans les sequenceDiagrams."
url: "https://www.arleo.eu/posts/debug-mermaid-svg-freeze/"
language: "fr"
datePublished: "2026-05-29T20:00:00+02:00"
dateModified: "2026-05-29T20:00:00+02:00"
tags: ["hugo","mermaid","svg","build","csp","infrastructure"]
categories: ["infrastructure","hardening"]
contentSignal: "ai-train=no, search=yes, ai-input=yes"
---

# Hugo : gel des diagrammes Mermaid en SVG statiques dark/light
Comment et pourquoi remplacer le rendu Mermaid côté client par des SVG statiques générés au build : paires dark/light via mmdc, hash de contenu, déduplication multilingue, et le piège &nbsp; dans les sequenceDiagrams.



## Problème

Les diagrammes Mermaid sur arleo.eu rendaient côté client via `cdn.jsdelivr.net`. Trois conséquences concrètes :

1. **CSP contrainte** — `script-src cdn.jsdelivr.net` et `worker-src cdn.jsdelivr.net` obligatoires (Mermaid v11 utilise des Web Workers pour ses parsers).
2. **Flash de rendu** — le diagramme apparaît après l'exécution JS, créant un décalage visible.
3. **Thème dark ignoré** — Mermaid initialisait le SVG en mode clair même quand le thème du site était dark.

La solution : générer les SVG **au build** avec `mmdc`, en dehors de tout contexte navigateur.

---

## Architecture : paires dark/light

`mmdc` (`@mermaid-js/mermaid-cli` v11.15.0) accepte un flag `--theme`. On génère systématiquement deux SVG par diagramme :

```bash
mmdc -i source.mmd -o diagram-{hash}-dark.svg  --theme dark
mmdc -i source.mmd -o diagram-{hash}-light.svg --theme default
```

Le shortcode Hugo `mermaid-svg` sélectionne le bon fichier selon l'attribut `theme` sur `<html>` :

```html
{{- $dark  := printf "diagram-%s-dark.svg"  .Get "hash" -}}
{{- $light := printf "diagram-%s-light.svg" .Get "hash" -}}
<img class="mermaid-svg mermaid-dark"  src="{{ $dark  | relURL }}" loading="lazy" />
<img class="mermaid-svg mermaid-light" src="{{ $light | relURL }}" loading="lazy" />
```

CSS dans `_custom.scss` :

```scss
html[theme=dark]  .mermaid-light { display: none; }
html[theme=light] .mermaid-dark  { display: none; }
html:not([theme]) .mermaid-dark  { display: none; }
```

---

## Implémentation dans hugo-mcp

La fonction `_freeze_mermaid_blocks()` dans `main.py` est appelée automatiquement lors de chaque `create_page` ou `update_page`.

**Détection :** regex sur les blocs ` ```mermaid `.

**Hash :** SHA256[:8] de la source brute. Même source = même hash entre FR et EN d'un même post — les SVG sont partagés, pas dupliqués.

**Marqueur de préservation :** le bloc est remplacé par :

```markdown
<!-- mermaid-source:BASE64_DE_LA_SOURCE -->
{{</* mermaid-svg hash="3007aa7f" */>}}
```

Le commentaire `mermaid-source` encode la source en base64. Lors d'une mise à jour ultérieure, si le hash calculé correspond au hash existant, les SVG ne sont pas régénérés. Si la source a changé, les anciens SVG sont remplacés.

**Nettoyage des orphelins :** avant de supprimer un SVG devenu inutile, le code scanne **tous** les fichiers `.md` du bundle (pas seulement le fichier en cours de traitement). Cela évite de supprimer un SVG encore référencé par la version sœur en cas de diagrammes identiques entre FR et EN.

---

## Bug : `&nbsp;` dans un sequenceDiagram

Le post `postmortem-cf-bot-blocking-mcp` contenait :

```
Note over CF: Custom Rule&nbsp;: host + path + IP range
```

`mmdc` échoue sur les entités HTML dans les labels :

```
Error: Parse error on line 8:
...Note over CF: Custom Rule&nbsp;: host + p
got 'TXT', expected [NEWLINE, 'end', 'COLON' ...]
```

**Fix :** nettoyage avant génération :

```bash
sed -i 's/&nbsp;/ /g' index.fr.md
```

Leçon : toujours utiliser des espaces Unicode normaux dans les sources Mermaid, jamais d'entités HTML.

---

## Résultats

- **12 posts** avec des diagrammes Mermaid, versions FR + EN
- **44 paires SVG** générées (dark + light)
- Certains posts FR/EN partagent les mêmes fichiers SVG (hash identique)
- Suppression de `worker-src cdn.jsdelivr.net` et `script-src cdn.jsdelivr.net` (Mermaid) du CSP
- Rendu immédiat, sans flash, thème respecté dès le premier paint
- Vérification Puppeteer : 0 image 404, 0 violation CSP, thème dark correctement appliqué

<!-- mermaid-source:Zmxvd2NoYXJ0IFRECiAgICBBWyJjcmVhdGVfcGFnZSAvIHVwZGF0ZV9wYWdlIl0gLS0+IEJbIl9mcmVlemVfbWVybWFpZF9ibG9ja3MoKSJdCiAgICBCIC0tPiBDeyJCbG9jIG1lcm1haWRcbmTDqXRlY3TDqSA/In0KICAgIEMgLS0gbm9uIC0tPiBEWyJDb250ZW51IGluY2hhbmfDqSJdCiAgICBDIC0tIG91aSAtLT4gRVsiU0hBMjU2Wzo4XVxuZGUgbGEgc291cmNlIl0KICAgIEUgLS0+IEZ7Ikhhc2ggZXhpc3RhbnRcbmRhbnMgU1ZHIGRpciA/In0KICAgIEYgLS0gbcOqbWUgaGFzaCAtLT4gR1siU1ZHIHLDqXV0aWxpc8OpcyJdCiAgICBGIC0tIG5vdXZlYXUvbW9kaWZpw6kgLS0+IEhbIm1tZGMgZGFya1xubW1kYyBsaWdodCJdCiAgICBIIC0tPiBJWyJkaWFncmFtLXtoYXNofS1kYXJrLnN2Z1xuZGlhZ3JhbS17aGFzaH0tbGlnaHQuc3ZnIl0KICAgIEkgLS0+IEpbIlNjYW4gdG91cyAubWRcbmR1IGJ1bmRsZSJdCiAgICBKIC0tPiBLWyJTdXBwcmltZSBTVkdzXG5vcnBoZWxpbnMgc8O7cnMiXQogICAgRyAtLT4gTFsiUmVtcGxhY2UgYmxvY1xucGFyIHNob3J0Y29kZSJdCiAgICBLIC0tPiBM -->
{{< mermaid-svg hash="5af4dcba" >}}


## Tags

- hugo
- mermaid
- svg
- build
- csp
- infrastructure

## Categories

- infrastructure
- hardening
