perf: trim observer work and defer Prism during streaming
- Drop characterData from scroll-follow and file-link MutationObservers; ResizeObserver already catches content growth. - extractMermaidBlocks: bail out when markdown has no 'mermaid' at all. - MarkdownCodeBlock: skip Prism highlighting while code is actively changing, render plain pre until settled for 300ms.
This commit is contained in:
@@ -484,6 +484,7 @@ type MermaidControlOptions = {
|
||||
};
|
||||
|
||||
const extractMermaidBlocks = (markdown: string): string[] => {
|
||||
if (!markdown.includes('mermaid')) return [];
|
||||
const blocks: string[] = [];
|
||||
const regex = /(?:^|\r?\n)(`{3,}|~{3,})mermaid[^\n\r]*\r?\n([\s\S]*?)\r?\n\1(?=\r?\n|$)/gi;
|
||||
let match: RegExpExecArray | null = regex.exec(markdown);
|
||||
@@ -679,12 +680,45 @@ const normalizeCodeBlockText = (code: string, language: string): string => {
|
||||
return decodeHtmlEntities(code);
|
||||
};
|
||||
|
||||
const CODE_HIGHLIGHT_SETTLE_MS = 300;
|
||||
const CODE_SHARED_STYLE: React.CSSProperties = {
|
||||
margin: 0,
|
||||
background: 'transparent',
|
||||
padding: 0,
|
||||
fontSize: 'var(--text-code)',
|
||||
lineHeight: 'var(--markdown-code-block-line-height)',
|
||||
};
|
||||
|
||||
const MarkdownCodeBlock: React.FC<{
|
||||
code: string;
|
||||
language: string;
|
||||
syntaxTheme: { [key: string]: React.CSSProperties };
|
||||
}> = ({ code, language, syntaxTheme }) => {
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
const [highlight, setHighlight] = React.useState(true);
|
||||
const prevCodeRef = React.useRef<string>(code);
|
||||
const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// Defer Prism highlighting while code is actively streaming.
|
||||
// Initial mount renders highlighted immediately (plays nice with finalized blocks).
|
||||
React.useEffect(() => {
|
||||
if (prevCodeRef.current === code) return;
|
||||
prevCodeRef.current = code;
|
||||
|
||||
if (timerRef.current) clearTimeout(timerRef.current);
|
||||
setHighlight(false);
|
||||
timerRef.current = setTimeout(() => {
|
||||
setHighlight(true);
|
||||
timerRef.current = null;
|
||||
}, CODE_HIGHLIGHT_SETTLE_MS);
|
||||
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [code]);
|
||||
|
||||
const handleCopy = React.useCallback(async () => {
|
||||
const result = await copyTextToClipboard(code);
|
||||
@@ -709,15 +743,21 @@ const MarkdownCodeBlock: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-3 py-2.5">
|
||||
<SyntaxHighlighter
|
||||
language={language}
|
||||
style={syntaxTheme}
|
||||
customStyle={{ margin: 0, background: 'transparent', padding: 0, fontSize: 'var(--text-code)', lineHeight: 'var(--markdown-code-block-line-height)' }}
|
||||
codeTagProps={{ style: { fontSize: 'var(--text-code)', lineHeight: 'var(--markdown-code-block-line-height)' } }}
|
||||
PreTag="pre"
|
||||
>
|
||||
{code}
|
||||
</SyntaxHighlighter>
|
||||
{highlight ? (
|
||||
<SyntaxHighlighter
|
||||
language={language}
|
||||
style={syntaxTheme}
|
||||
customStyle={CODE_SHARED_STYLE}
|
||||
codeTagProps={{ style: CODE_SHARED_STYLE }}
|
||||
PreTag="pre"
|
||||
>
|
||||
{code}
|
||||
</SyntaxHighlighter>
|
||||
) : (
|
||||
<pre style={CODE_SHARED_STYLE}>
|
||||
<code style={CODE_SHARED_STYLE}>{code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -1256,7 +1296,6 @@ const useFileReferenceInteractions = ({
|
||||
observer.observe(container, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
characterData: true,
|
||||
});
|
||||
|
||||
container.addEventListener('click', handleClick);
|
||||
|
||||
@@ -159,7 +159,7 @@ export const useScrollEngine = ({
|
||||
resize.observe(container);
|
||||
|
||||
const mutation = new MutationObserver(onChange);
|
||||
mutation.observe(container, { childList: true, subtree: true, characterData: true });
|
||||
mutation.observe(container, { childList: true, subtree: true });
|
||||
|
||||
followObserversRef.current = { resize, mutation };
|
||||
}, [containerRef, runFollowBurst]);
|
||||
|
||||
Reference in New Issue
Block a user