Bug Description
Syntax highlighting is lost when a DiffView component is unmounted and then remounted with the same file content. The first render shows correct syntax highlighting, but subsequent renders show plain text without any highlight classes.
Steps to Reproduce
- Render a
DiffView with diffViewHighlight enabled and a registerHighlighter (e.g., lowlight)
- Unmount the component (e.g., navigate away)
- Remount the component with the same diff data
- Expected: Syntax highlighting appears as on the first render
- Actual: No syntax highlighting — all code is plain text
Root Cause
The issue is in the syntax initialization effect across all framework packages (React, Vue, Svelte, Solid).
When DiffView remounts, the following sequence occurs:
useMemo creates a new DiffFile instance
initRaw() calls #doFile() → getFile(), which returns a cached File from the global _cacheMap. This cached File carries highlighterName and highlighterType from the first render.
initRaw() → #syncSyntax() copies these values to the new DiffFile
- The syntax effect checks:
if (
registerHighlighter.name !== diffFile._getHighlighterName() ||
registerHighlighter.type !== diffFile._getHighlighterType() ||
registerHighlighter.type !== "class"
)
- Since
#syncSyntax already copied "lowlight" and "class" from the cached File, all three conditions are false
initSyntax() is never called, leaving #newFileSyntaxLines and #oldFileSyntaxLines as null
- The diff renders with
diff-line-content-raw (plain text) instead of diff-line-syntax-raw (highlighted)
DOM Evidence
First render (working):
<span class="diff-line-syntax-raw">
<span class="hljs-keyword">class</span>
<span class="hljs-title class_">CherryPickInput</span>
...
</span>
Second render (broken):
<span class="diff-line-content-raw">
<span data-template="true">class CherryPickInput(BaseModel):</span>
</span>
Suggested Fix
The effect's guard condition is too aggressive. initSyntax() is already idempotent — when syntax is already initialized with a matching highlighter, it efficiently re-syncs syntax line references without recomputing. The effect should always call initSyntax() when highlighting is enabled, rather than trying to skip it based on highlighter metadata that may have been inherited from the global File cache.
Affected files:
packages/react/src/components/DiffView.tsx
packages/vue/src/components/DiffView.tsx
packages/svelte/src/lib/components/DiffView.svelte
packages/solid/src/components/DiffView.tsx
Bug Description
Syntax highlighting is lost when a
DiffViewcomponent is unmounted and then remounted with the same file content. The first render shows correct syntax highlighting, but subsequent renders show plain text without any highlight classes.Steps to Reproduce
DiffViewwithdiffViewHighlightenabled and aregisterHighlighter(e.g., lowlight)Root Cause
The issue is in the syntax initialization effect across all framework packages (React, Vue, Svelte, Solid).
When
DiffViewremounts, the following sequence occurs:useMemocreates a newDiffFileinstanceinitRaw()calls#doFile()→getFile(), which returns a cachedFilefrom the global_cacheMap. This cachedFilecarrieshighlighterNameandhighlighterTypefrom the first render.initRaw()→#syncSyntax()copies these values to the newDiffFile#syncSyntaxalready copied"lowlight"and"class"from the cachedFile, all three conditions arefalseinitSyntax()is never called, leaving#newFileSyntaxLinesand#oldFileSyntaxLinesasnulldiff-line-content-raw(plain text) instead ofdiff-line-syntax-raw(highlighted)DOM Evidence
First render (working):
Second render (broken):
Suggested Fix
The effect's guard condition is too aggressive.
initSyntax()is already idempotent — when syntax is already initialized with a matching highlighter, it efficiently re-syncs syntax line references without recomputing. The effect should always callinitSyntax()when highlighting is enabled, rather than trying to skip it based on highlighter metadata that may have been inherited from the globalFilecache.Affected files:
packages/react/src/components/DiffView.tsxpackages/vue/src/components/DiffView.tsxpackages/svelte/src/lib/components/DiffView.sveltepackages/solid/src/components/DiffView.tsx