Skip to content

Commit b65d194

Browse files
Merge pull request #2210 from netease-youdao/fix/mermaid-artifact-error-overflow
fix(artifacts): prevent Mermaid error SVG leaking
2 parents d9bb6ce + 77253dd commit b65d194

1 file changed

Lines changed: 35 additions & 3 deletions

File tree

src/renderer/components/artifacts/renderers/MermaidRenderer.tsx

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ function initMermaid(isDark: boolean) {
1414
mermaidInitialized = true;
1515
}
1616

17+
function cleanupMermaidRenderArtifacts(id: string) {
18+
document.getElementById(id)?.remove();
19+
document.getElementById(`d${id}`)?.remove();
20+
document.getElementById(`i${id}`)?.remove();
21+
}
22+
23+
function createMermaidRenderContainer(): HTMLDivElement {
24+
const container = document.createElement('div');
25+
container.setAttribute('data-lobster-mermaid-render-container', 'true');
26+
container.style.position = 'absolute';
27+
container.style.left = '0';
28+
container.style.top = '0';
29+
container.style.width = '100%';
30+
container.style.visibility = 'hidden';
31+
container.style.overflow = 'hidden';
32+
container.style.pointerEvents = 'none';
33+
document.body.appendChild(container);
34+
return container;
35+
}
36+
1737
interface MermaidRendererProps {
1838
artifact: Artifact;
1939
}
@@ -50,22 +70,34 @@ const MermaidRenderer: React.FC<MermaidRendererProps> = ({ artifact }) => {
5070

5171
let cancelled = false;
5272
const renderDiagram = async () => {
73+
const id = `mermaid-${artifact.id.replace(/[^a-zA-Z0-9]/g, '')}`;
74+
let renderContainer: HTMLDivElement | null = null;
5375
try {
54-
const id = `mermaid-${artifact.id.replace(/[^a-zA-Z0-9]/g, '')}`;
55-
const { svg: rendered } = await mermaid.render(id, artifact.content);
76+
cleanupMermaidRenderArtifacts(id);
77+
await mermaid.parse(artifact.content);
78+
renderContainer = createMermaidRenderContainer();
79+
const { svg: rendered } = await mermaid.render(id, artifact.content, renderContainer);
5680
if (!cancelled) {
5781
setSvg(rendered);
5882
setError(null);
5983
}
6084
} catch (err) {
6185
if (!cancelled) {
86+
setSvg('');
6287
setError(err instanceof Error ? err.message : 'Failed to render diagram');
6388
}
89+
} finally {
90+
renderContainer?.remove();
91+
cleanupMermaidRenderArtifacts(id);
6492
}
6593
};
6694

6795
renderDiagram();
68-
return () => { cancelled = true; };
96+
return () => {
97+
cancelled = true;
98+
const id = `mermaid-${artifact.id.replace(/[^a-zA-Z0-9]/g, '')}`;
99+
cleanupMermaidRenderArtifacts(id);
100+
};
69101
}, [artifact.content, artifact.id]);
70102

71103
if (error) {

0 commit comments

Comments
 (0)