blog.hangerthem.com/lib/mermaid-render.ts
2026-08-03 20:00:40 +02:00

62 lines
1.8 KiB
TypeScript

import { Browser, launch } from 'puppeteer'
let browserPromise: Promise<Browser> | null = null
function getBrowser() {
if (!browserPromise) {
browserPromise = launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
})
}
return browserPromise
}
/**
* Closes the Puppeteer browser instance if it exists.
* This function is useful for cleaning up resources when the application is shutting down or when the browser is no longer needed.
*/
export async function closeMermaidBrowser() {
if (browserPromise) {
const browser = await browserPromise
await browser.close()
browserPromise = null
}
}
const cache = new Map<string, string>()
/**
* Renders a Mermaid chart to SVG using Puppeteer and caches the result.
* @param chart - The Mermaid chart definition as a string.
* @returns A promise that resolves to the rendered SVG string.
*/
export async function renderMermaidToSvg(chart: string): Promise<string> {
const cached = cache.get(chart)
if (cached) return cached
const browser = await getBrowser()
const page = await browser.newPage()
try {
await page.setContent(`
<!DOCTYPE html>
<html><body><div id="target"></div></body></html>
`)
await page.addScriptTag({
url: 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js',
})
const svg = await page.evaluate(async (source) => {
// @ts-expect-error mermaid is loaded globally via the script tag above
window.mermaid.initialize({ startOnLoad: false, theme: 'neutral' })
// @ts-expect-error same as above
const { svg: renderedSvg } = await window.mermaid.render('mermaid-diagram', source)
return renderedSvg
}, chart)
cache.set(chart, svg)
return svg
} finally {
await page.close()
}
}