Teaching the blog to draw: Mermaid at build time
#mermaid #copilot #astro #security #supply-chain
In the previous post I walked through how this site is hosted, and used a diagram to do it. That diagram is not a screenshot or a hand-drawn SVG: it is Mermaid, written as plain text in Markdown. It fits my markdown-as-content approach nicely, so I wanted it wired in properly rather than bolted on.
The whole thing is rendered to a static image at build time, so the page ships zero JavaScript for diagrams and needed no changes to the site’s strict Content-Security-Policy. Here is what went in, most of it driven by asking Copilot and then keeping it on task:
What went in
- Pre-rendered, not client-side. Diagrams are turned into inline SVG during the build with
@beoe/rehype-mermaid(credit to its maintainer, it wraps the renderer with a build cache), so the browser gets a plain<svg>and none of the heavy Mermaid runtime. That keeps the zero-JS, snappy-loading profile intact. - Headless Chromium. Mermaid needs a DOM to render, so the build drives a headless Chromium (via Playwright). It is a build-only dependency, wired into the dev container so it survives rebuilds, and the rendered SVGs are cached so rebuilds do not re-run the browser.
- A highlighting gotcha. Astro highlights code blocks with Shiki, the same syntax highlighter that powers VS Code, and it grabbed the
mermaidblocks before the plugin could. So I had to excludemermaidfrom Shiki to hand the raw block to the renderer. - CSP-safe by design. Because it is inline SVG with no runtime script, the strict Content-Security-Policy needed no changes. Copilot’s first instinct was the client-side library, which would have forced me to loosen the CSP, a nice reminder that the tool’s default is not always the secure one.
- On-brand and theme-aware. The diagram is themed to the CRT phosphor palette, and because the SVG is inline I could recolour it with a little CSS so it follows the green/amber toggle along with the rest of the site.
The stale dependency in the room
Speaking of installing a pile of npm packages just to draw a box and an arrow: that is exactly the kind of thing that can quietly ship a malicious postinstall and walk off with your cloud credentials. The very plugin drawing these diagrams has not shipped a release in about a year, and I used it anyway, because it only runs at build time and, worst case, I can fork it. On a client’s production system I would think twice; on a personal blog, with no users and no data to lose, it is a calculated bet I am happy to make. How I weigh that difference, and lock down the rest, deserves its own post, so more on securing the supply chain soon.
References
The tools and docs that made this possible, if you want to dig deeper:
- VS Code — where all of this actually gets written.
- GitHub Copilot — the pair-programmer that drafted most of it, and occasionally needed talking out of a bad idea.
- Mermaid — diagrams-as-text, the thing doing the drawing.
@beoe/rehype-mermaid— the build-time renderer and cache that keeps it zero-JS.- Playwright — drives the headless Chromium that Mermaid needs to render.
- Shiki — the syntax highlighter behind Astro’s code blocks (and VS Code’s).