Proof of Concept — Non-blocking rendering using hidden iframes as isolated rendering workers
document.getElementById() and writes directly into DOM elements.
Pure Web Workers have no DOM access.
Hidden iframes provide the best of both worlds: each iframe has its own DOM and its own JavaScript execution context, so rendering does not block the main thread.
This is the same isolation model that GitHub already uses for Mermaid diagrams.
Each ```plantuml block gets its own hidden <iframe> that acts as a dedicated rendering worker. All iframes render in parallel without blocking the main thread or each other.
Finds ```plantuml blocks.
Creates one hidden iframe per diagram.
Sends source via postMessage.
Main thread stays free.
Loads engine once.
Has its own DOM context.
Renders SVG off-screen.
Sends SVG string back.
Receives SVG string.
Inserts into visible DOM.
Destroys worker iframe.
// This HTML page is loaded into each hidden iframe. // It contains <script> tags for viz-global.js and plantuml.js, // plus this listener: plantumlLoad(); const target = document.createElement('div'); target.id = 'out'; document.body.appendChild(target); window.addEventListener('message', (event) => { const { lines, requestId, dark } = event.data; const observer = new MutationObserver(() => { if (target.querySelector('svg')) { observer.disconnect(); window.parent.postMessage({ requestId, svg: target.innerHTML }, '*'); } }); observer.observe(target, { childList: true, subtree: true }); window.plantuml.render(lines, 'out', dark ? { dark: true } : undefined); });
function renderInWorker(lines, targetId, dark) { const requestId = 'puml-' + targetId + '-' + Date.now(); // Create a hidden iframe as a rendering worker const iframe = document.createElement('iframe'); iframe.src = 'plantuml-worker-frame.html'; iframe.style.cssText = 'display:none'; document.body.appendChild(iframe); // Listen for the result function onMessage(e) { if (e.data.requestId !== requestId) return; window.removeEventListener('message', onMessage); // Insert SVG into the visible target document.getElementById(targetId).innerHTML = e.data.svg; // Destroy the worker iframe iframe.remove(); } window.addEventListener('message', onMessage); // Send the render request once the iframe is ready iframe.addEventListener('load', () => { iframe.contentWindow.postMessage( { lines, requestId, dark }, '*' ); }); }
Here's our authentication flow:
And here's the deployment topology: