Repository navigation
perf(inbox): load the emoji name table on first use - #2774
Conversation
#2638 imported reaction-name statically in InboxRow, which put the emoji-mart name table (native.json, ~413 KB) into the first-paint closure. move StatusEmoji's load-once import() into a shared useReactionName hook and use it in both; reaction rows fall back to the raw emoji until the table arrives. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Kalvin Chau <[email protected]>
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord automated source review via Wes’s account, with independent Rocket, Mantis and Groot coverage.
No actionable findings in the three-file change. The shared loader preserves per-consumer unmount guards and current-value lookup; Activity retains a Unicode fallback until names load, while custom shortcode labels and StatusEmoji tooltip behavior are preserved. Existing asynchronous label assertions were inspected.
Reviewed head e8b138060465965ddad4cd66d86940d9917b1bec against target base fb9cd7cf45c6d80368cc79a7c34535f8f3b2fd20 (merge-base 8c0cb0c1efb68068b89c813ad6f890d8b8f07401). Source only: no tests, builds, app, screen-reader or CI execution. The reported performance measurements and test results were not independently verified.
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 the shared hook keeps the module-level cache and the per-consumer unmount guard, useEmojiName behaves the same, and the inbox tests already wait for the named label with findByRole. one nonblocking test suggestion inline
| reaction.emoji | ||
| ? `:${reaction.emoji.shortcode}:` | ||
| : reactionName(reaction.content) | ||
| : (reactionName?.(reaction.content) ?? reaction.content) |
There was a problem hiding this comment.
🤖 nonblocking: nothing tests the label before the table loads ("reacted with ❤️", then "reacted with heart" once it arrives). mocking ./reaction-name behind a deferred promise and asserting both labels would pin down the fallback this adds
…leanup * origin/main: test(mentions): serve the mentions fixture as a build so cold loads fit (#2776) test(browser): let a late publication land after its page closed (#2565) test(relay): wait for the verified owner before a guest edits an agent (#2413) test: wait for the companion default width measurement (#2750) test(browser): preserve conversation scroll while revealing actions (#2715) test(browser): wait for link hit-testing after thread close (#2792) perf(messages): skip micromark for plain prose bodies (#2780) perf(inbox): load the emoji name table on first use (#2774) perf(messages): cut main-thread work while a busy channel is open (#2729) Refine agent Attention cards, watch details, and status controls (#2717) fix(bestie): remove a Bestie from its agent card on any device (#2720) feat(agents): preview Builderlab agent card links with Add to Buzz (#2719)
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell <[email protected]> Signed-off-by: Tyler Longwell <[email protected]> * origin/main: test(messages): wait for the row measurement frame before thread catch-up dwell (#2837) Keep agent coordination history readable after work finishes (#2454) test(mentions): serve the mentions fixture as a build so cold loads fit (#2776) test(browser): let a late publication land after its page closed (#2565) test(relay): wait for the verified owner before a guest edits an agent (#2413) test: wait for the companion default width measurement (#2750) test(browser): preserve conversation scroll while revealing actions (#2715) test(browser): wait for link hit-testing after thread close (#2792) perf(messages): skip micromark for plain prose bodies (#2780) perf(inbox): load the emoji name table on first use (#2774) perf(messages): cut main-thread work while a busy channel is open (#2729) Refine agent Attention cards, watch details, and status controls (#2717) fix(bestie): remove a Bestie from its agent card on any device (#2720) feat(agents): preview Builderlab agent card links with Add to Buzz (#2719) Restore macOS Cmd-W window closing when no tab handles it (#2443) Make agent transcripts quieter and link finished replies to activity (#2424)
…ve-enter * origin/main: (21 commits) Make drafts and sent part of Messages (#2728) fix(canvas): render every Canvas within the save limit (#2839) test(messages): wait for the row measurement frame before thread catch-up dwell (#2837) Keep agent coordination history readable after work finishes (#2454) test(mentions): serve the mentions fixture as a build so cold loads fit (#2776) test(browser): let a late publication land after its page closed (#2565) test(relay): wait for the verified owner before a guest edits an agent (#2413) test: wait for the companion default width measurement (#2750) test(browser): preserve conversation scroll while revealing actions (#2715) test(browser): wait for link hit-testing after thread close (#2792) perf(messages): skip micromark for plain prose bodies (#2780) perf(inbox): load the emoji name table on first use (#2774) perf(messages): cut main-thread work while a busy channel is open (#2729) Refine agent Attention cards, watch details, and status controls (#2717) fix(bestie): remove a Bestie from its agent card on any device (#2720) feat(agents): preview Builderlab agent card links with Add to Buzz (#2719) Restore macOS Cmd-W window closing when no tab handles it (#2443) Make agent transcripts quieter and link finished replies to activity (#2424) fix(channels): wrap unread conversation stepping around the sidebar (#2682) fix(navigation): let bare buzz:// open Buzz without a broken-link notice (#2718) ...
Co-authored-by: BuzzPRReviewAssistant1 <a581a7e8115222acdc32ffb14bfce55d48c24478d98e155f8eba126b69b83c7b@buzz.block.builderlab.xyz> * origin/main: (71 commits) test(activity): scope preview assertions to the request row (#2843) perf(search): fold people names once across palette keystrokes (#2570) fix(github): keep PR watches running when localStorage is full (#2699) Make drafts and sent part of Messages (#2728) fix(canvas): render every Canvas within the save limit (#2839) test(messages): wait for the row measurement frame before thread catch-up dwell (#2837) Keep agent coordination history readable after work finishes (#2454) test(mentions): serve the mentions fixture as a build so cold loads fit (#2776) test(browser): let a late publication land after its page closed (#2565) test(relay): wait for the verified owner before a guest edits an agent (#2413) test: wait for the companion default width measurement (#2750) test(browser): preserve conversation scroll while revealing actions (#2715) test(browser): wait for link hit-testing after thread close (#2792) perf(messages): skip micromark for plain prose bodies (#2780) perf(inbox): load the emoji name table on first use (#2774) perf(messages): cut main-thread work while a busy channel is open (#2729) Refine agent Attention cards, watch details, and status controls (#2717) fix(bestie): remove a Bestie from its agent card on any device (#2720) feat(agents): preview Builderlab agent card links with Add to Buzz (#2719) Restore macOS Cmd-W window closing when no tab handles it (#2443) ... Signed-off-by: Ravneet Arora <[email protected]>
…ime-hint * upstream/main: (26 commits) Make drafts and sent part of Messages (block#2728) fix(canvas): render every Canvas within the save limit (block#2839) test(messages): wait for the row measurement frame before thread catch-up dwell (block#2837) Keep agent coordination history readable after work finishes (block#2454) test(mentions): serve the mentions fixture as a build so cold loads fit (block#2776) test(browser): let a late publication land after its page closed (block#2565) test(relay): wait for the verified owner before a guest edits an agent (block#2413) test: wait for the companion default width measurement (block#2750) test(browser): preserve conversation scroll while revealing actions (block#2715) test(browser): wait for link hit-testing after thread close (block#2792) perf(messages): skip micromark for plain prose bodies (block#2780) perf(inbox): load the emoji name table on first use (block#2774) perf(messages): cut main-thread work while a busy channel is open (block#2729) Refine agent Attention cards, watch details, and status controls (block#2717) fix(bestie): remove a Bestie from its agent card on any device (block#2720) feat(agents): preview Builderlab agent card links with Add to Buzz (block#2719) Restore macOS Cmd-W window closing when no tab handles it (block#2443) Make agent transcripts quieter and link finished replies to activity (block#2424) fix(channels): wrap unread conversation stepping around the sidebar (block#2682) fix(navigation): let bare buzz:// open Buzz without a broken-link notice (block#2718) ... Signed-off-by: Cheng Peng <[email protected]> Co-authored-by: Cursor <[email protected]>
## Why `user-status.spec.mjs`, "statuses edit, synchronize, clear, reject stale traffic and retain failed drafts", fails intermittently on WebKit with an unexplained page error: `Unhandled Promise Rejection: TypeError: Importing a module script failed.` | Sighting | Lane | |---|---| | [9 Nov, PR](https://github.com/block/buzz-app/actions/runs/42573912834/job/129017542663), and again on [its re-run](https://github.com/block/buzz-app/actions/runs/42573912834/job/129030209036) | Flake check, WebKit 2/11 | | [10 Nov, main](https://github.com/block/buzz-app/actions/runs/42766553248/job/129664645706) | Browser journeys, WebKit 9/18 | | [11 Nov, PR](https://github.com/block/buzz-app/actions/runs/42981535351/job/130393321764) | Flake check, WebKit 2/12 | The spec's check for unexplained page errors is deliberate and correct. The bug is in the product. ## Root cause `useReactionName` and `ReactionEmoji`'s `revealName` both ran `void import("./reaction-name").then(...)` with no rejection handler. `reaction-name.ts` statically imports the emoji-mart native table, so the first Unicode status or reaction name starts a large chunk load. When a navigation lands while that load is in flight, WebKit cancels the request, the `import()` rejects, and the page reports an unhandled rejection. In the journey, the click that opens a free-text status starts the load and the next `page.goto` cancels it. The traces show the chunk request failing with "Load request cancelled" and the page error 4 ms after the navigation. The unguarded import arrived with #2384 and moved into `useReactionName` in #2774. ## Fix Handle the rejection at both sites. - A failed load leaves the name unresolved. In the hook the next mount tries again. `ReactionEmoji` keeps the raw content and the next hover or focus tries again. - Both handlers `console.warn` with the error, so a chunk that keeps failing, such as a 404 after a deploy with a stale shell, stays visible. The comments note that only a new document fetches the chunk again, because some engines keep a failed module fetch for the document's life. The warning does not affect browser checks: the fixture records only error-level console messages, and the page-error helper watches `pageerror`. There is no spec or fixture change, and the page-error check stays as it is. The second commit is the review follow-up that replaced the first commit's empty handlers with the warning and made the two unit tests wait for it. ## Tests - `use-reaction-name.test.tsx` (new) and a `MessageReactions.test.tsx` case mock `./reaction-name` to reject. They assert the name stays unresolved, that the warning is logged, and that no unhandled rejection reaches the process. They then unmock and show the next mount or reveal resolves. - On the unfixed code both fail with the unhandled rejection. ## Evidence | Scope | Result | |---|---| | This branch's head, macOS: `bin/pnpm exec vitest run src/features/messages/use-reaction-name.test.tsx src/features/messages/MessageReactions.test.tsx` | 2 files, 29 passed | | Before the split from a combined branch, Linux: the same two files | 27 passed in 8 of 8 runs, no stderr output | | Linux, WebKit: `user-status.spec.mjs`, `--workers=1 --repeat-each=8` | 8/8 passed, 11.7 to 12.7 s each | | Triage, WebKit, with the native table request held across the navigation | unfixed 3/3 failed with the CI error, fixed 3/3 passed | | Before the split, Linux: Biome on the touched files, `tsc --noEmit` | clean | The count is 29 here and 27 in the commit messages because #3397 has since added tests to `MessageReactions.test.tsx`. ## Not reproduced, not run - The cancelled chunk did not reproduce on an idle host without holding the request, so the WebKit repeat guards against regression rather than reproducing CI timing. - Not tried in the desktop app. The user-visible change is the absence of an unhandled rejection, plus a console warning when the chunk fails. - The local pre-push checks for this branch (whole-project type check, related unit tests, design-system check) were not run. The two-file run in the first row is the only check run on this branch's head. The type check and Biome results are from the combined branch, where the same change passed. - No human has tested this yet, so `buzz-review-completed` is not set. ## Left alone - A second, unrelated failure of the same journey ("Duration: Today" read as "8 hours" at exactly 16:00 UTC) is fixed in its own PR. - In the persistent-failure case each hover or new mount logs another warning. That is bounded and only visible in developer tools. - Open PRs #2896, #2120, #2085 and #2009 edit other parts of `MessageReactions.tsx`, and #2794, #2154 and #2120 edit its test file. A trial merge of each against this change is clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: mtoohey <[email protected]> Signed-off-by: Matt Toohey <[email protected]> Co-authored-by: Claude Fable 5.1 <[email protected]>
Problem
#2638 added reaction rows to the Activity inbox.
InboxRow.tsximportsreactionNamestatically to build each row's accessible label. That one import putfeatures/messages/reaction-nameand its emoji-mart name table (@emoji-mart/data/sets/15/native.json, a 413 KB chunk) into the first-paint closure. Every launch now downloads, parses and evaluates the table and builds itsMap, whether or not a reaction row is ever shown.MessageReactionsandStatusEmojialready load the same module withimport().Change
useReactionNamehook (features/messages/use-reaction-name.ts) loadsreaction-namewithimport()once, caches it at module level and rerenders when the table arrives. This is the load-once codeuseEmojiNameinStatusEmojialready had, moved so it can be shared.ReactionRowButtonanduseEmojiNameboth use the hook, so one table load serves both.Behavior
aria-labeluses the emoji character, for example "reacted with ❤️". It switches to the name, "reacted with heart", once the table loads. The first reaction row to mount fetches the chunk.Evidence
Cold start of a production build in Chromium at 4× CPU throttling, from navigation to the first frame with the app shell rendered. Main
8c0cb0c1eand this PR ran as 12 interleaved samples each on one Linux and one macOS workstation. The table shows medians.Lower is better.
index.html. Thenativechunk (412,954 B) leaves it, andmaingrows by 273 B for the dynamic import.Checks:
src/bundled/inboxandsrc/features/user-statusvitest suites pass (239 tests).tscandbiomepass.reaction-name.🤖 Generated with Claude Code