Docusaurus Prerender Mermaid Plugin: Statische & barrierefreie Mermaid-Diagramme
Informationen zum Artikel

Autor: Dmitry Dugarev
Ein Plugin für Docusaurus, das Deine Mermaid-Diagramme zur Build-Zeit in statische SVG- oder PNG-Bilder vorab rendert.
Dies löst häufige Probleme beim clientseitigen Rendern von Mermaid, wie langsame Performance, Content Layout Shift (CLS) und insbesondere die Zugänglichkeits- und SEO-Probleme, die durch fehlenden alt-Text, Bildunterschriften, Textbeschreibungen und eine schlechte semantische HTML-Struktur verursacht werden.
Demo-Beispiel
So würdest Du ein Diagramm in Deiner .md- oder .mdx-Datei schreiben:
- Mermaid-Code
- Generiertes HTML
- Gerendertes Bild
Nutze die Meta-Felder im Frontmatter-ähnlichen Block, um id, alt-Text, caption (Bildunterschrift) und aria-describedby für Barrierefreiheit hinzuzufügen.
```mermaid
---
id: company-flow
alt: Ein Flussdiagramm, das den Unternehmensprozess zeigt.
caption: Der offizielle Unternehmens-Entwicklungsprozess.
width: 300px
descriptionId: company-flow-desc
date: 2025-11-03T16:00:00+01:00
---
graph TD
A[Sales] --> B(Development);
B --> C{Testing};
C --> D[Deployment];
```
Die obige Mermaid-Markdown wird während der Build-Zeit in folgendes HTML umgewandelt, wenn Du beide Themes (Hell & Dunkel) aktiviert hast:
<figure id="company-flow" class="static-mermaid-figure">
<!-- Dieses <img> wird nicht auf der Seite sein, wenn in der Konfiguration nur das helle Thema aktiviert ist -->
<img
width="500px"
class="mermaid-light"
src="/img/diagrams/company-flow-de-light.svg"
alt="Ein Flussdiagramm, das den Unternehmensprozess zeigt."
aria-labelledby="company-flow-caption"
aria-describedby="company-flow-desc"
/>
<!-- Dieses <img> wird nicht auf der Seite sein, wenn in der Konfiguration nur das dunkle Thema aktiviert ist -->
<img
width="500px"
class="mermaid-dark"
src="/img/diagrams/company-flow-de-dark.svg"
alt="Ein Flussdiagramm, das den Unternehmensprozess zeigt."
aria-labelledby="company-flow-caption"
aria-describedby="company-flow-desc"
/>
<figcaption id="company-flow-caption">
Der offizielle Unternehmens-Entwicklungsprozess.
</figcaption>
</figure>
Je nach Konfiguration wird nur das <img> für das helle oder dunkle Theme gerendert, oder beide, wenn der Theme-Wechsel aktiviert ist.
Beim Theme-Wechsel zeigt Docusaurus automatisch das richtige Bild an und blendet das andere aus, ohne dass JavaScript erforderlich ist - es geschieht sofort über CSS.
Weil das eine Bild mit display: none ausgeblendet ist, wird es aus dem Accessibility Tree entfernt und von Screenreadern ignoriert, sodass nur das sichtbare Bild vorgelesen wird.
Hier ist, wie das gerenderte Diagramm auf der Website aussieht:
Beschreibung des Unternehmensprozess-Diagramms.
Dieses Diagramm veranschaulicht die Hauptphasen unseres Unternehmensprozesses, beginnend beim Verkauf, über die Entwicklung, gefolgt vom Testen und endend mit der Bereitstellung.
Was ist das und warum?
Standardmäßig rendern Docusaurus und @docusaurus/theme-mermaid Diagramme auf der Client-Seite. Das bedeutet, dass der Browser jedes Besuchers die Mermaid.js-Bibliothek ausführen muss, um Deinen Diagrammtext zu parsen und in ein Bild umzuwandeln.
Dieser Ansatz hat mehrere Probleme:
- Schlechte Performance: Es fügt Deiner Website zusätzliches JavaScript hinzu, was die Ladezeiten erhöht.
- Layout Shift: Ein "Aufblitzen" von ungestyltem Code erscheint, bevor das Diagramm gerendert wird, was dazu führt, dass Dein Seiteninhalt "springt" (ein schlechter Core Web Vital-Wert).
- Kein statischer Export: Diagramme erscheinen nicht in RSS-Feeds, Social-Media-Vorschauen oder anderen Umgebungen ohne JavaScript.
- Zugänglichkeitsprobleme: Der clientseitige Renderer fügt keinen
alt-Text oder Bildunterschriften hinzu, wodurch Diagramme für Screenreader unzugänglich werden. Er verwendet auch keine semantischen HTML-Elemente wie<figure>und<figcaption>und es ist unmöglich, mittelsaria-describedbyauf externe Textbeschreibungen zu verlinken. - SEO-Probleme: Suchmaschinen können den Inhalt Deiner Diagramme nicht indizieren, was Deiner SEO schaden kann.
Dieses Plugin behebt all das, indem es das Rendering einmal zur Build-Zeit (npm run build) durchführt. Es generiert statische <img>-Tags, was zu einer blitzschnellen Erfahrung ohne Layout-Verschiebung für Deine Benutzer führt. Für die Barrierefreiheit umschließt es jedes Diagramm mit einem korrekten <figure>-Element und unterstützt Bildunterschriften in <figcaption>, alt-Text und aria-describedby für Textbeschreibungen.
Funktionen
- Statisches Rendering: Konvertiert
mermaid-Blöcke in statische<img>-Tags. - Dark/Light-Modus-Unterstützung: Rendert automatisch helle und dunkle Versionen Deiner Diagramme basierend auf Deinen Docusaurus-Theme-Einstellungen.
- Barrierefrei: Generiert einen HTML-
<figure>-Wrapper mit<img>und<figcaption>für Screenreader und fülltalt-Text, Bildunterschrift undaria-describedbyunter Verwendung der Metadaten Deines Diagramms aus. - Metadaten-Unterstützung: Verwende einen Frontmatter-ähnlichen Block in Deinem Diagramm, um eine
id,alt-Text,caption(Bildunterschrift) hinzuzufügen und überaria-describedbyauf eine Textbeschreibung zu verlinken. - Vollständig konfigurierbar: Integriert sich direkt in Deine
docusaurus.config.ts, einschließlichthemeConfig.mermaid. - Caching: Bereits gerenderte Diagramme werden übersprungen, was nachfolgende Builds beschleunigt.
- Anpassbare Ausgabe: Wähle zwischen SVG- und PNG-Formaten, lege Ausgabeverzeichnisse fest und übergebe benutzerdefinierte Argumente an die Mermaid-CLI.
- Parallelitätssteuerung: Konfiguriere, wie viele Diagramme parallel gerendert werden sollen, um eine optimale Build-Leistung zu erzielen.
Wie es funktioniert
Das Plugin arbeitet in drei Phasen:
Textbeschreibung für das Diagramm "Übersicht über den Workflow des Docusaurus
Prerender Mermaid Plugins."
Dieses Flussdiagramm veranschaulicht die drei Hauptphasen des Workflows des Docusaurus Prerender Mermaid Plugins:
-
Build-Zeit (Haupt-Plugin):
- Durchsucht Deine Inhaltsverzeichnisse (
docs,blogusw.) nach allenmermaid-Blöcken. - Liest Deine
docusaurus.config.ts, um Deine Theme-Namen für Hell und Dunkel für Mermaid zu finden. Wenn Du einemermaid.config.json-Datei hast, werden stattdessen die Einstellungen von dort verwendet. - Wenn Dein Farbmodus-Wechsel über
themeConfig.mermaid.disableColorModedeaktiviert ist, wird nur das eine Standard-Theme gerendert, das inthemeConfig.colorMode.defaultModedefiniert ist. - Es ruft
@mermaid-js/mermaid-cli(mmdc) auf, um zwei Bilder für jedes Diagramm zu rendern (z. B.diagram-de-light.svgunddiagram-de-dark.svg), wenn der Theme-Wechsel aktiviert ist, oder nur ein Bild, wenn er deaktiviert ist. - Es speichert diese Bilder im Verzeichnis
static/img/diagrams(oder Deinem konfiguriertenoutputDir). - Cacht gerenderte Diagramme, um zukünftige Builds zu beschleunigen.
- Wenn Docusaurus den Build-Prozess startet, kopiert es diese Bilder automatisch von
static/in das endgültigebuild/-Verzeichnis.
- Durchsucht Deine Inhaltsverzeichnisse (
-
Inhalts-Transformation (Remark-Plugin):
- Während der Markdown-zu-HTML-Konvertierung fängt das Remark-Plugin den
mermaid-Block ab. - Es ersetzt den Code-Block durch eine HTML-
<figure>-Struktur. - Innerhalb der Figure fügt es zwei
<img>-Tags ein, die auf die statischen Dateien verweisen (oder eines, wenn der Theme-Wechsel deaktiviert ist). prerender: false-Diagramme werden übersprungen und für den clientseitigen Renderer unverändert belassen.- Es füllt Barrierefreiheits-Attribute wie
alt,aria-labelundaria-describedbyunter Verwendung der im Diagrammblock bereitgestellten Metadaten aus. - Wenn eine Bildunterschrift (
caption) bereitgestellt wird, fügt es ein<figcaption>-Element unter den Bildern hinzu. - Im Entwicklermodus (
npm run start) wird der ursprüngliche Mermaid-Renderer für eine Live-Vorschau und schnellere Bearbeitungen angezeigt, der mit derselben Struktur wie die statische Ausgabe modifiziert wird (mit<figure>,<img>und<figcaption>), um der Build-Ausgabe so nahe wie möglich zu kommen.
- Während der Markdown-zu-HTML-Konvertierung fängt das Remark-Plugin den
-
Client-Seite (Browser):
- Das Plugin injiziert eine winzige CSS-Datei, die das
[data-theme='dark']-Attribut von Docusaurus verwendet, um das korrekte<img>anzuzeigen und das andere auszublenden. Dieser Wechsel erfolgt sofort und erfordert kein JavaScript.
- Das Plugin injiziert eine winzige CSS-Datei, die das
Installation & Einrichtung
Du musst das Plugin aus der npm-Registry installieren:
npm install @barrierenlos/docusaurus-prerender-mermaid
Du musst das Plugin an zwei Stellen in Deiner docusaurus.config.ts hinzufügen:
- Das Haupt-Plugin im root-
plugins-Array. - Das Remark-Plugin in Deinen docs/blog/pages-Preset-Optionen.
// docusaurus.config.ts
import type { Config } from '@docusaurus/types';
// 1. Importiere das Remark-Plugin
import remarkMermaidStatic from '@barrierenlos/docusaurus-prerender-mermaid/remark';
const config: Config = {
// ...
i18n: {
defaultLocale: 'de',
locales: ['de', 'en', 'ru'],
},
themeConfig: {
// ...
// Das Plugin liest diese Konfiguration automatisch!
mermaid: {
theme: { light: 'neutral', dark: 'dark' },
options: {
fontFamily: 'Arial, sans-serif',
},
},
},
// 2. Füge das Haupt-Plugin hinzu
plugins: [
[
'@barrierenlos/docusaurus-prerender-mermaid',
{
// Plugin-Optionen...
contentPaths: ['docs', 'legal'], // Zu scannende Verzeichnisse
outputDir: 'static/img/diagrams', // Wohin die Bilder geschrieben werden sollen
outputFormat: 'svg', // 'svg' oder 'png'
// concurrency: 4, // Wie viele gleichzeitig gerendert werden sollen. Standard: CPU-Anzahl
mmdcArgs: ['-b', 'transparent'], // Zusätzliche mmdc-Argumente
// andere Optionen...
},
],
// ... andere Plugins
],
presets: [
[
'classic',
{
docs: {
// 3. Füge das Remark-Plugin hinzu
beforeDefaultRemarkPlugins: [remarkMermaidStatic],
// ... andere Docs-Optionen
},
blog: {
// 3. Füge das Remark-Plugin hinzu (falls Du Mermaid im Blog verwendest)
beforeDefaultRemarkPlugins: [remarkMermaidStatic],
// ... andere Blog-Optionen
},
// ...
} satisfies Preset.Options,
],
],
};
export default config;
Konfigurationsoptionen
Alle Optionen sind optional und werden an das Haupt-Plugin in docusaurus.config.ts übergeben.
| Option | Beschreibung | Standard |
|---|---|---|
contentPaths | Ein Array von Inhaltsverzeichnissen, die nach Diagrammen durchsucht werden sollen, relativ zu siteDir. | ['docs', 'blog'] |
outputDir | Das Verzeichnis, in das gerenderte Bilder ausgegeben werden sollen, relativ zum static-Verzeichnis. | 'img/diagrams' |
outputFormat | Das Ausgabeformat. Kann 'svg' oder 'png' sein. | 'svg' |
configFile | Pfad zu einer physischen mermaid.config.json-Datei. Falls angegeben, überschreibt dies themeConfig.mermaid.config für Basis-Stile. | 'mermaid.config.json' |
concurrency | Die Anzahl der Diagramme, die gleichzeitig gerendert werden sollen. | os.cpus().length |
mmdcArgs | Ein Array von zusätzlichen String-Argumenten, die an die mmdc-CLI übergeben werden sollen. | ['-b', 'transparent'] |
outputSuffixes | Die Suffixe, die für helle und dunkle Themes angehängt werden sollen. | { light: '-light', dark: '-dark' } |
Konfigurationsbeispiele
Standardkonfiguration (Minimal)
Wenn Du mit allen Standardeinstellungen zufrieden bist, musst Du nur das Plugin registrieren. Das Remark-Plugin benötigt keine Optionen.
import remarkMermaidStatic from 'docusaurus-prerender-mermaid/remark';
const config: Config = {
// ...
plugins: [
'docusaurus-prerender-mermaid',
// ...
[
'@docusaurus/plugin-content-docs',
{
id: 'your-custom-id',
path: 'your-custom-path',
// ...
beforeDefaultRemarkPlugins: [remarkMermaidStatic],
},
],
],
presets: [
[
'classic',
{
docs: {
beforeDefaultRemarkPlugins: [remarkMermaidStatic],
// ...
},
// ...
},
],
],
};
Erweiterte (Vollständige) Konfiguration
Dieses Beispiel ändert die Inhaltsverzeichnisse, den Ausgabepfad und fügt mmdc einen benutzerdefinierten Skalierungsfaktor hinzu.
import remarkMermaidStatic from 'docusaurus-prerender-mermaid/remark';
const config: Config = {
// ...
plugins: [
[
'docusaurus-prerender-mermaid',
{
contentPaths: ['docs', 'legal', 'src/pages'],
outputDir: 'static/assets/mermaid',
outputFormat: 'png',
concurrency: 4,
mmdcArgs: ['-b', 'transparent', '--scale', '1.5'],
},
],
// ...
],
presets: [
[
'classic',
{
docs: {
beforeDefaultRemarkPlugins: [remarkMermaidStatic],
// ...
},
},
],
],
// ...
};
Mermaid-Metadaten
Du kannst einen Metadaten-Block (ähnlich wie Frontmatter) oben in jeden mermaid -Block einfügen. Dies gibt Dir eine feingranulare Kontrolle über Barrierefreiheit und Styling.
Verfügbare Metadaten-Felder
Hier sind die verfügbaren Metadaten-Optionen, die Du verwenden kannst:
| Option | Typ / Standard | Beschreibung |
|---|---|---|
id | String | Setzt die HTML-id für das <figure>-Tag. Falls nicht angegeben, wird ein 10-stelliger Hash des Diagrammcodes verwendet. Diese ID definiert auch den Namen der Ausgabebilddateien. |
alt | String | Dringend empfohlen. Setzt den alt-Text für die <img>-Tags. Entscheidend für die Barrierefreiheit – beschreibe das Diagramm aussagekräftig (unter 160 Zeichen). |
caption | String | Fügt ein <figcaption>-Element unter dem Diagramm hinzu. |
width | String | Setzt das width-Attribut auf den <img>-Tags (z. B. 600px). Nützlich, wenn gerenderte Bilder auf dem Desktop zu groß sind. |
prerender | false | Wenn auf false gesetzt, wird dieses Plugin dieses Diagramm vollständig überspringen und es dem clientseitigen @docusaurus/theme-mermaid zum Rendern überlassen. |
descriptionId | String | Erweiterte Barrierefreiheitsfunktion, die die Figure über aria-describedby mit einer externen Beschreibung verknüpft. Verwende die id eines vorhandenen HTML-Elements, das den Beschreibungstext enthält (für WCAG-Konformität). |
Styling-Anleitung
Die Diagramme werden ohne Standard-Styling ausgeliefert, sodass Du sie an das Design Deiner Website anpassen kannst.
.static-mermaid-figure: Der Haupt-<figure>-Wrapper..mermaid-light: Das<img>-Tag für das helle Theme..mermaid-dark: Das<img>-Tag für das dunkle Theme.figcaption: Das Bildunterschrift-Element.
SCSS-Styling-Beispiel
Hier ist ein erweitertes Beispiel (unter Verwendung von SCSS), um Deinen Bildern einen Hintergrund, border-radius und benutzerdefinierte nummerierte Zähler hinzuzufügen.
.static-mermaid-figure {
// Einen Zähler für jede Figure hinzufügen
counter-increment: figurecounter;
margin: 2rem 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem; // Abstand zwischen Bild und Bildunterschrift
// Die img-Tags stylen
& > img {
max-width: 100%;
max-height: 100%;
padding: 1.5rem;
background-color: var(--ifm-card-background-color);
border-radius: 0.75rem;
border: 1px solid var(--ifm-color-emphasis-300);
}
// Die Bildunterschrift stylen
& > figcaption {
margin-top: 0.25rem;
font-size: 0.9rem;
color: var(--ifm-font-color-secondary);
font-style: italic;
text-align: center;
// Beispiel für einen benutzerdefinierten "Abbildung 1.1: "-Zähler
&::before {
content: 'Abbildung ' counter(h2counter) '.' counter(figurecounter) ': ';
font-weight: 600;
color: var(--ifm-font-color-base);
font-style: normal;
}
}
}
Lizenz
Dieses Plugin wird unter der MIT-Lizenz veröffentlicht. Es steht Dir frei, es nach Belieben zu verwenden, zu ändern und zu verteilen.
Mitwirken
Beiträge sind willkommen! Wenn Du einen Fehler findest oder einen Funktionswunsch hast, eröffne bitte ein Issue im GitHub-Repository.