Displaying Excalidraw Diagrams in Nuxt
How I added Excalidraw diagram support to my Nuxt site, including failed attempts at build-time SVG conversion and the simpler solution using Obsidian's auto-export.
The Problem
I created an Excalidraw diagram in Obsidian and embedded it in a markdown note using {.excalidraw-diagram}. When rendered in Nuxt, nothing appeared—the wiki-link module only handled [slug](/slug){.wiki-link} links, not image embeds.
Understanding the File Format
Obsidian's Excalidraw plugin stores diagrams as .excalidraw.md files containing LZ-String compressed JSON in a compressed-json code block. The actual drawing data is base64-encoded and compressed.
Attempt 1: Build-Time Decompression and SVG Conversion
My first approach was to decompress the JSON at build time and convert it to SVG using excalidraw-to-svg. This required:
lz-stringfor decompressionexcalidraw-to-svgfor rendering@excalidraw/utilsfor the conversion utilities
Result: Failed. The excalidraw-to-svg library uses jsdom to simulate a DOM, but it requires the canvas npm package which needs native dependencies (Cairo, Pango via Homebrew). Too much friction for a simple diagram.
Attempt 2: Using Obsidian's Auto-Export
The Excalidraw plugin has a setting to auto-export SVG files alongside the .excalidraw.md files. With this enabled, Obsidian creates a .svg file automatically whenever you save a diagram.
Result: Success. The build script just copies these pre-rendered SVGs to public/excalidraw/.
The SVG Theming Problem
The exported SVGs have hardcoded colors:
- White background:
fill="#ffffff" - Dark strokes/text:
stroke="#1e1e1e"
This doesn't adapt to dark mode. My first instinct was to replace colors with currentColor, but that doesn't work—<img> tags load SVGs as static images without CSS context.
Solution: CSS Filter for Dark Mode
- Build script removes the white background rect via regex
- CSS uses
filter: invert(1) hue-rotate(180deg)for dark mode
.excalidraw-diagram {
max-height: 70vh;
object-fit: contain;
}
.dark .excalidraw-diagram {
filter: invert(1) hue-rotate(180deg);
}
The hue-rotate(180deg) preserves color relationships after inverting—without it, colors would shift unexpectedly.
Final Implementation
Files created/modified:
scripts/build-excalidraw.ts- Copies and processes SVGsmodules/wikilinks.ts- Transforms{.excalidraw-diagram}to<img>tagsapp/assets/css/main.css- Styling and dark mode support
Pipeline:
Obsidian auto-export → content/Excalidraw/*.svg
Build script → public/excalidraw/*.svg (background removed)
Wiki-link transform → <img class="excalidraw-diagram" src="/excalidraw/slug.svg">
Key Takeaway
When a "proper" solution requires complex dependencies, look for what the tool already provides. Obsidian's auto-export feature eliminated the need for build-time SVG generation entirely.