From 380f8dfded551988cbc20cf350ac8a765428638e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 23 Oct 2026 06:08:26 +0000 Subject: [PATCH] perf(chat): optimize signature string generation Replaced Array.join with template literal concatenation for `messagesSignature` and `sig` in `ChatThread.tsx`. By avoiding unnecessary array allocation on string building, we reduce memory pressure and garbage collection overhead during rapid frontend streaming and continuous polling. Co-authored-by: bobdivx <6737167+bobdivx@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ apps/web/src/components/chat/ChatThread.tsx | 12 ++---------- apps/web/src/lib/chat-messages.ts | 9 ++------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index edb6874221..cddafcc0b0 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -5,3 +5,7 @@ ## 2026-10-15 - [Performance] Prevent unnecessary UI array recalculations **Learning:** In the chat component (`useThreadList`), derived state that requires filtering and sorting large arrays (like generating nested agent lists) was running synchronously on every render. Given that chat polling triggers frequent re-renders, this caused unnecessary CPU strain on lists that only rarely change. **Action:** Use `useMemo` for derived states like `rows` and `current` in custom hooks when they involve `.filter()`, `.map()`, or `.sort()` and depend on data that updates less frequently than the component renders. + +## 2026-10-23 - [Performance] Avoid `Array.join()` on hot paths for string building +**Learning:** In frequently called functions or render hooks during polling (like `messagesSignature` and `useStickToBottom`), constructing signatures using `[val1, val2, ...].join('|')` unnecessarily allocates arrays and causes garbage collection overhead. Since polling and re-renders happen continuously, these small allocations add up to noticeable memory pressure. +**Action:** Use direct template literals (e.g., `${val1}|${val2}`) for simple string concatenations in performance-critical paths instead of array mapping or joining. diff --git a/apps/web/src/components/chat/ChatThread.tsx b/apps/web/src/components/chat/ChatThread.tsx index 50a0209c1b..f765399ce5 100644 --- a/apps/web/src/components/chat/ChatThread.tsx +++ b/apps/web/src/components/chat/ChatThread.tsx @@ -18,16 +18,8 @@ export function useStickToBottom(messages: ChatMessage[], resetKey: unknown) { if (!box) return; // On ne défile que si le contenu a réellement changé. const last = messages[messages.length - 1]; - const sig = [ - messages.length, - last?.content.length ?? 0, - last?.toolCalls?.length ?? 0, - last?.actions?.length ?? 0, - last?.reflections?.length ?? 0, - last?.milestones?.length ?? 0, - last?.liveLabel ?? '', - last?.streaming ? 1 : 0, - ].join('|'); + // Avoid Array allocation and join on hot path + const sig = `${messages.length}|${last?.content.length ?? 0}|${last?.toolCalls?.length ?? 0}|${last?.actions?.length ?? 0}|${last?.reflections?.length ?? 0}|${last?.milestones?.length ?? 0}|${last?.liveLabel ?? ''}|${last?.streaming ? 1 : 0}`; if (sig === lastSig.current) return; const first = lastSig.current === ''; lastSig.current = sig; diff --git a/apps/web/src/lib/chat-messages.ts b/apps/web/src/lib/chat-messages.ts index 4b5db18523..c075dfbe67 100644 --- a/apps/web/src/lib/chat-messages.ts +++ b/apps/web/src/lib/chat-messages.ts @@ -50,13 +50,8 @@ export function messagesSignature(messages: IdentifiedMessage[]): string { } } - return [ - messages.length, - last?.id ?? '', - last?.content.length ?? 0, - last?.toolCalls?.length ?? 0, - reactionsSig, - ].join('|'); + // Avoid Array allocation and join on hot path + return `${messages.length}|${last?.id ?? ''}|${last?.content.length ?? 0}|${last?.toolCalls?.length ?? 0}|${reactionsSig}`; } /**