Two guards protect the core promise: a route with no islands emits no
assets at all, and a page with several islands keeps React in one shared
chunk.
buildIslands now writes a generated entry per island instead of passing
component sources directly. Two islands sharing a source deduped to a
single entrypoint, and output order is not guaranteed to match input
order, so island names could bind to the wrong bundle.
Island modules are excluded from the editor compiler bundle: it globs
packages/compiler/src, and island-bundle.ts calls Bun.build while
island-codegen.ts imports @wrnexus/core — neither belongs in a Node-only
VS Code artifact.
Integration assertions share one build. bun test interferes with
Bun.build's module reads after several build calls in one process, while
the same calls succeed repeatedly outside the runner; production is
unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Disposes and re-creates island roots after a source change. Island state
resets by design; Fast Refresh needs a Babel/SWC transform plus a
runtime and is out of scope for v1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds /__wrnexus/islands.js (the bootstrap) and the /__wrnexus/island/
prefix (mount runtime, island bundles, shared chunks) to all three
serving paths.
Dev reuses the browserArtifactPaths registry pattern from pipeline.ts.
Prod mirrors the clientModulesDir handler, including its filename
allowlist, so island names cannot escape the output directory.
The bootstrap is inert without a data-wrn-island marker, so island-free
pages still download nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mounts markers with client:only/load/visible/idle, and disposes roots on
route change so React roots, detached DOM, and store subscriptions do
not leak across client-side navigation.
Bundle load failures and malformed props JSON degrade to a warning and
leave the server markup intact rather than taking down the page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A crashed island renders its error in dev and nothing in prod, leaving
the surrounding server-rendered page intact.
Island .tsx sources carry an explicit @jsxImportSource react pragma: the
repo's root tsconfig points jsxImportSource at @wrnexus/core, so without
it island JSX compiles to WRNexus's string renderer instead of React
elements.
Tests render on the client via createRoot rather than a server renderer,
because React error boundaries do not engage during SSR — and islands
are client-only regardless.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolves WRNexus stores from inside islands, reading through the cached
snapshot so React sees a stable reference. Unknown store names throw
with the list of registered stores rather than failing opaquely.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
useSyncExternalStore requires getSnapshot to return an identical
reference when unchanged; @wrnexus/store's readonlySnapshot returns a
fresh clone per call. The cache lives here rather than in the store
package so existing consumers are untouched.
createSelectorCache takes an optional equality function: the Object.is
default can never stabilize a selector that allocates, which is the
usual source of infinite re-renders.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>