perf(notebook): skip re-rendering unchanged cell outputs while typing (#34334)

This commit is contained in:
OrcaWin
2026-10-27 11:43:05 -07:00
committed by GitHub
parent 05fc67ff51
commit d45d579ea4
3 changed files with 47 additions and 3 deletions
@@ -1,4 +1,4 @@
import { useMemo } from 'react'
import { memo, useMemo } from 'react'
import { formatToolDuration } from '../../../../shared/native-chat/tools/native-chat-tool-identity'
import { IpynbCellOutputs } from './IpynbCellOutputs'
import { IpynbRunPrompt } from './IpynbCellToolbar'
@@ -30,7 +30,8 @@ export function IpynbCellRunPrompt({
}
/** A cell's outputs: live from its run until the document takes them in, then from the document. */
export function IpynbCellRunOutputs({
// Why: every keystroke re-renders the viewer, and re-parsing each cell's saved outputs costs ms.
export const IpynbCellRunOutputs = memo(function IpynbCellRunOutputs({
filePath,
cellKey,
cell
@@ -50,4 +51,4 @@ export function IpynbCellRunOutputs({
[cell, run]
)
return <IpynbCellOutputs cell={live ?? cell} />
}
})
@@ -0,0 +1,40 @@
// @vitest-environment happy-dom
import { cleanup, render, screen } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { i18n } from '@/i18n/i18n'
import { IpynbCellRunOutputs } from './IpynbCellRun'
import type { IpynbCell } from './ipynb-parse'
vi.mock('@/hooks/use-document-dark-theme', () => ({ useDocumentDarkTheme: () => false }))
const cell: IpynbCell = {
id: 'cell-1',
kind: 'code',
language: 'python',
source: 'df',
executionCount: 1,
outputs: [
{
kind: 'display',
outputType: 'display_data',
executionCount: null,
items: [{ mime: 'text/html', value: '<table></table>' }]
}
]
}
afterEach(async () => {
cleanup()
await i18n.changeLanguage('en')
})
describe('memoized notebook cell outputs', () => {
it('relabels HTML output when the UI language changes without new props', async () => {
await i18n.changeLanguage('en')
render(<IpynbCellRunOutputs filePath="/nb.ipynb" cellKey="cell-1" cell={cell} />)
expect(screen.getByTitle('Notebook HTML output')).toBeTruthy()
await i18n.changeLanguage('es')
expect(await screen.findByTitle('Salida HTML del notebook')).toBeTruthy()
})
})
@@ -1,5 +1,6 @@
import { useMemo } from 'react'
import DOMPurify from 'dompurify'
import { useTranslation } from 'react-i18next'
import { translate } from '@/i18n/i18n'
import { useDocumentDarkTheme } from '@/hooks/use-document-dark-theme'
@@ -19,6 +20,8 @@ const OUTPUT_DOCUMENT_HEAD = `<!doctype html><meta charset="utf-8">
</style>`
export function IpynbHtmlOutput({ html }: { html: string }): React.JSX.Element {
// Why: memoized cell outputs skip parent re-renders, so subscribe to language changes here.
useTranslation()
const colorScheme = useDocumentDarkTheme() ? 'dark' : 'light'
const srcDoc = useMemo(
() =>