ReviewOS

stacks/stx

streaming/islands: resumability (Qwik-style) — research spike

#1753
Closed glennmichael123 opened this 14 days ago · 1 comment
14 days ago

Spun out of #1746 (now feature-complete and closed). Phase 4 — resumability — was always scoped there as out-of-near-term research, so tracking it separately.

Goal

Skip hydration entirely: serialize component state + lazily wire events on first interaction (Qwik-style), instead of re-running setup on the client. The deepest, most speculative part of the islands direction.

Why separate

#1746 delivered the shippable architecture — opt-in islands (client="…", per-island chunking) and streaming SSR (dev + production, streamBoundaries/@stream, in-boundary hydration). Resumability is a different model (serialize-and-resume vs hydrate) and warrants its own design spike rather than blocking the umbrella.

Starting points

  • The island scope IIFEs and data-stx-scope/data-stx-island wiring already isolate per-component setup.
  • window.stx._stores SSR hydration (window.__STX_STORE_STATE__) is a precedent for serializing state.
  • Event wiring is centralized in the signals runtime's processElement — a candidate seam for lazy/deferred event attachment.

Research spike: prototype serialize-state + lazy-event-wiring for one island; measure vs the current hydrate path.

14 days ago

Spike done — written up in docs/features/resumability-spike.md (b6e0882f30).

Recommendation: don't pursue full resumability. Pursue the part of it that pays.

The blocking finding

Resumability in Qwik is a compiler contract the author opts into, not a runtime feature. Serialising a component scope means serialising closures:

const items = state([])
const visible = derived(() => items().filter(i => !i.done))
function toggle(item) { items.update(…) }

items() serialises. visible is a function over items — you can serialise its value, but resuming it means reconstructing the dependency edge without running the module. toggle can't be serialised at all, which is exactly why Qwik requires every such function to be a separately-addressable lazy symbol ($()).

stx's contract — plain functions in a <script client> block — is structurally incompatible with that. So this is an authoring-model change, not an implementation detail, and that reframes the cost entirely.

Two further costs: it adds a third state (declared-but-not-constructed) to a reactive core that already has two implementations required to stay equivalent, and lazy wiring introduces precisely the indirection the recent silent-failure work has been removing.

What we already have, and it's real

Your three starting points all hold up: per-component scope isolation is the right serialisation unit, window.__STX_STORE_STATE__ is a working precedent, and processElement is a genuine single seam for lazy attachment. That's why this warranted a spike rather than a flat no.

The alternative

The measurable win on a typical stx page isn't the hydrate walk — it's that every page ships the whole runtime and runs setup for components the user may never touch. Two changes capture most of it:

  1. Per-island runtime splitting. The prod runtime is 39KB gzipped and the binders are the bulk of it; a page with no :for needn't ship bindFor. Bundler change, no authoring impact.
  2. Interaction-triggered hydration as the default for below-fold islands — stx-hydrate="interaction" already does this, from #1746.

Both are incremental, both preserve the authoring model, both are measurable.

Falsifiable

The doc ends with the smallest decisive experiment for anyone who wants to challenge this: one island, one @click, scope serialised to a data-stx-resume attribute, wire-up replaced by a delegated listener, measured against the same island hydrated normally. That isolates the single claim everything else rests on. If reconstruct-on-demand doesn't beat run-setup-once for a realistic component, the rest of the design doesn't matter.

Closing as the spike it was scoped to be. Worth reopening if the authoring contract ever changes for another reason — that would make the serialisation work tractable and this conclusion should be revisited.

Sign in to comment on this issue.