From 33333c3945d77d8a88800ed55647b1e15542bd3b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 14:06:26 +0000 Subject: [PATCH 1/2] fix: buffer rsc:update payloads arriving before dev client mounts In devMain, the rsc:update HMR listener was registered before the component's mount effect assigned setPayload, so an update event racing the initial render called undefined and threw, dropping the update. Keep the fetched payload in a pending variable when the setter is not ready yet and apply it from the mount effect. Fixes #145 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CAcPFym3wyHJQyMb2FdgqT --- packages/static/src/client/entry.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/static/src/client/entry.tsx b/packages/static/src/client/entry.tsx index 1a7149a..a801c17 100644 --- a/packages/static/src/client/entry.tsx +++ b/packages/static/src/client/entry.tsx @@ -18,7 +18,10 @@ import { withBasePath } from "../util/basePath"; import { ssr as ssrEnabled } from "virtual:funstack/config"; async function devMain() { - let setPayload: (v: RscPayload) => void; + let setPayload: ((v: RscPayload) => void) | undefined; + // Holds an update that arrived before the component mounted; the mount + // effect applies it so early rsc:update events are not dropped. + let pendingPayload: RscPayload | undefined; const initialPayload = await createFromReadableStream(rscStream); @@ -27,6 +30,11 @@ async function devMain() { useEffect(() => { setPayload = (v) => startTransition(() => setPayload_(v)); + if (pendingPayload !== undefined) { + const payload = pendingPayload; + pendingPayload = undefined; + setPayload(payload); + } }, [setPayload_]); return payload.root; @@ -40,7 +48,11 @@ async function devMain() { location.pathname, )}`; const payload = await createFromFetch(fetch(rscUrl)); - setPayload(payload); + if (setPayload) { + setPayload(payload); + } else { + pendingPayload = payload; + } } const browserRoot = ( From de3c07463afe73b91b453c60f6cf4eabf6d0c783 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 14:11:22 +0000 Subject: [PATCH 2/2] refactor: initialize setPayload with a pending-buffer setter Per review, replace the undefined check in fetchRscPayload with an initial setPayload implementation that stashes the payload until the mount effect swaps in the real setter. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CAcPFym3wyHJQyMb2FdgqT --- packages/static/src/client/entry.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/static/src/client/entry.tsx b/packages/static/src/client/entry.tsx index a801c17..a247ef4 100644 --- a/packages/static/src/client/entry.tsx +++ b/packages/static/src/client/entry.tsx @@ -18,10 +18,12 @@ import { withBasePath } from "../util/basePath"; import { ssr as ssrEnabled } from "virtual:funstack/config"; async function devMain() { - let setPayload: ((v: RscPayload) => void) | undefined; // Holds an update that arrived before the component mounted; the mount // effect applies it so early rsc:update events are not dropped. let pendingPayload: RscPayload | undefined; + let setPayload: (v: RscPayload) => void = (v) => { + pendingPayload = v; + }; const initialPayload = await createFromReadableStream(rscStream); @@ -48,11 +50,7 @@ async function devMain() { location.pathname, )}`; const payload = await createFromFetch(fetch(rscUrl)); - if (setPayload) { - setPayload(payload); - } else { - pendingPayload = payload; - } + setPayload(payload); } const browserRoot = (