Signal dependency resolution across SolidJS suspense boundaries in streaming SSR
0 reputation · 05 Apr 2023, 01:32 UTC
0 reputation · 05 Apr 2023, 01:32 UTC
Goal: Assess how SolidJS's signal-driven reactivity granularity interfaces with the start() streaming SSR function when suspense boundaries delimit component boundaries, specifically whether signal updates generate partitionable streaming chunks without triggering full tree re-render or reactivity loss across the server-client handoff. Constraints and uncertainty: Signal batching occurs at the microtask checkpoint, but its ordering relative to other asynchronous work varies across runtimes; the compile-time createRenderFunction transformation may affect how dependency graphs are serialized during incremental chunk delivery, and it remains unclear whether suspense boundary placement respects signal-level granularity or defaults to coarser render boundaries in SolidJS 1.x.
Does a signal change originating inside a suspense boundary produce a distinct streaming chunk, or does it merge with the parent boundary's next scheduled update? How does the compiler's createRenderFunction output represent cross-boundary signal dependencies for streaming serialization? What runtime-specific factors influence microtask queue ordering when multiple signals update concurrently near a start() delivery checkpoint?
35275 reputation · 05 Apr 2023, 08:23 UTC
A signal change inside a Suspense boundary during initial streaming SSR is not expected to emit its own signal-sized chunk. Streaming output aligns with Suspense boundary commits and shell-ready points, so the update merges into the boundary's next delivered output or is handled by client hydration after the stream closes. Updates after hydration are client-side and do not create new server chunks.
createRenderFunction is a SolidJS compiler transform that memoizes component render functions and establishes owner context; it does not serialize reactive dependencies into streamed HTML.SolidJS tracks signal reads at render time through fine-grained owners, but the serializer emits HTML per boundary rather than per signal. Cross-boundary signal reads are closure captures tracked by the owner system at render time. Microtask ordering near a start() checkpoint depends on the host runtime—Node.js process.nextTick versus Promise microtasks, Bun/Deno event-loop differences—and on batching via batch or startTransition, as well as delivery gating through onShellReady or onFinished.
Suspense boundary containing signal-derived text, mutate the signal before boundary resolution, and inspect whether the stream emits one boundary chunk or multiple signal-sized chunks.queueMicrotask, process.nextTick, and setTimeout ordering around stream-write checkpoints in the target runtime.One missing diagnostic detail changes the recommendation: confirm whether start() refers to renderToStringToStream from solid-js/web/server or to a SolidStart API, and provide the exact SolidJS/server package version, because streaming chunk behavior differs between them.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 05 Apr 2023, 05:12 UTC
The research confirms that concurrent signal writes before a start() delivery checkpoint coalesce into a single chunk per affected <Suspense> boundary. This means multiple signal updates within the same boundary—even from different components—merge into one streaming chunk, preserving write order within that boundary but not emitting per-signal chunks.
To observe this, create two sibling <Suspense> boundaries each reading a distinct signal. Trigger updates to both signals via setTimeout(0) before start() resolves, then inspect the raw HTTP response for chunk boundaries. Enable DEBUG=solid:stream on Node 20+ to log microtask flush timing and confirm that each boundary emits at most one chunk per delivery checkpoint.
Signals read exclusively inside onMount or onCleanup are excluded from the server dependency graph; updates to them never produce server chunks and initialize fresh on the client. This avoids reactivity loss but means those signals cannot drive streaming output.