Repository navigation
perf(messages): prepare a message once for its renderer and link previews - #3466
Merged
Merged
Conversation
…iews finding a message's link previews prepared and scanned its markdown again and kept no result, so every mount of a link-bearing row parsed its body two or three more times than a row without links, and again on each remount while scrolling. link previews now share the renderer's cache of recent prepared bodies, take the scan a fresh preparation made instead of scanning again, and keep recent preview link lists the same way. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Kalvin Chau <[email protected]>
kalvinnchau
marked this pull request as ready for review
November 13, 2026 15:29
wpfleger96
reviewed
Nov 13, 2026
wpfleger96
left a comment
Member
There was a problem hiding this comment.
🤖 no blocking findings from me. the scan handed back from prepareMarkdown is the final scan of the normalized content, and a cache hit falls back to scanning the prepared content like before. MessageRow computes previewUrls in its own render before MessageMarkdown renders, so the preview-first order the new test covers is the one that happens in practice. the preview-link key includes the exclusions, and nothing downstream mutates the frozen lists.
wpfleger96
approved these changes
Nov 13, 2026
wpfleger96
left a comment
Member
There was a problem hiding this comment.
🤖 approving, no blocking findings (details in the earlier review).
joshfriend
added a commit
that referenced
this pull request
Nov 13, 2026
* origin/main: (153 commits) feat(agents): preview where interrupted agents were working before resume (#3494) perf(messages): close the editor and delete dialog on submit (#3493) feat(messages): quote selected message text into the composer (#2392) perf(toast): scope docked clearance to the toast host (#3489) fix(unread): undo exact captured ordinary reads conditionally (#3473) fix(solo): keep navigation responsive during chat deletion (#3488) fix(channels): keep custom thread tab names until the tab closes (#3458) perf(relay): verify cached history in the native host (#3426) fix(settings): refine claude and typesafe key setup dialogs (#3391) Update bundled help for Bestie and agent settings (#3194) feat(profiles): share and show a local time zone (#3332) Revert "feat(link-previews): unfurl web links below messages by default" (#3480) Show disabled plugin chats in Solo (#3456) perf(messages): host one context menu per message list (#3465) test(claude): keep the quit-release test copy above the minimum version (#3477) fix(profiles): restore verified names from the device cache (#3382) fix(mentions): show addressed agents first in Solo audience picker (#2856) perf: count member access once and scope find highlights to painting (#3464) perf(messages): prepare a message once for its renderer and link previews (#3466) fix(composer): speed up long pastes and paste office text as text (#3441) ... # Conflicts: # docs/plugin-authoring-guide.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Link previews (#3219, #3225) find a message's preview URLs with
previewLinks. For any body with anhttps://link, that function calledprepareMarkdown, then scanned the prepared content again withscanMarkdown, and kept no result. The renderer already prepares the same body through its own cache.A link-bearing row therefore parsed its Markdown two or three more times than a row without links, on every mount. It did this again on each remount while scrolling or switching channels.
Change
markdown-preparation.ts:recentResultsandpreparedBodiesmove here fromMessageMarkdown.tsx, unchanged.preparedMarkdown(content, scanned?).prepareMarkdowntakes an optionalscannedcallback that receives the scan it made. It stays pure and keeps no state.MessageMarkdown.tsxreads throughpreparedMarkdown, with the same cache and budget as before.preview-links.ts:preparedMarkdown. On a fresh preparation it takes the scan through the callback instead of scanning again.recentResultscache. The key is the content and exclusions; the weight counts both the key and the URLs. Cached lists are frozen.preview-links.test.tsasserts that the renderer and previews together scan a body once. This fails on the previous code.Why behaviour is unchanged
prepareMarkdownis pure, so a cached prepared body is identical to a fresh one.content, the same input previews scanned before.Evidence
Interleaved A/B on 9 Linux and 9 macOS boxes:
The baseline is
main(7bb45482) with #3464 and #3465 applied. This change was measured on top of that. The measured revision handed the scan over through module state instead of a callback; the parse count is the same. A variant with preview scanning disabled entirely is the ceiling.Checks
vitest run src/features/messages: 3119 pass.link-previews.specandmarkdown-documents.specpass on chromium and webkit.bin/pnpm checkis clean.🤖 Generated with Claude Code