perf(desktop): isolate streaming re-renders & cut layout thrash

During a token stream $messages is replaced ~30x/s. Subscribing the whole
chat view to it re-rendered the composer, runtime boundary, and every
message on every delta.

- Derive coarse facts (empty thread? tail is user?) via nanostores
  `computed` atoms so per-token flushes don't re-render their consumers.
- Move the $messages subscription + runtime wiring into a dedicated
  ChatRuntimeBoundary; the composer reads $messages imperatively.
- Drive message rows off stable useAuiState selectors and a lazy
  getMessageText getter instead of eagerly materialized text.
- Feed ResizeObserver entry sizes into measureClamp / FadeText and dedupe
  the style writes, killing the read-write-read reflow cascade.
This commit is contained in:
Brooklyn Nicholson
2026-06-12 21:07:33 -05:00
parent a86b7b314b
commit 7c226cc57f
7 changed files with 297 additions and 136 deletions
+13 -4
View File
@@ -1,17 +1,26 @@
import { type RefObject, useLayoutEffect, useRef } from 'react'
export function useResizeObserver(onResize: () => void, ...refs: readonly RefObject<Element | null>[]) {
/**
* Observe element resizes. The callback receives the ResizeObserver entries
* (empty on the initial synchronous call and in non-RO environments) so
* callers can read the observed size off the entry instead of forcing a
* fresh layout read.
*/
export function useResizeObserver(
onResize: (entries: readonly ResizeObserverEntry[]) => void,
...refs: readonly RefObject<Element | null>[]
) {
const refsRef = useRef(refs)
refsRef.current = refs
useLayoutEffect(() => {
if (typeof ResizeObserver === 'undefined') {
onResize()
onResize([])
return
}
const observer = new ResizeObserver(() => onResize())
const observer = new ResizeObserver(entries => onResize(entries))
let observed = false
for (const ref of refsRef.current) {
@@ -31,7 +40,7 @@ export function useResizeObserver(onResize: () => void, ...refs: readonly RefObj
return
}
onResize()
onResize([])
return () => observer.disconnect()
}, [onResize])