@sigx/ssr-islands · Stable

Islands#

@sigx/ssr-islands adds islands architecture to SignalX SSR: ship a static, server-rendered page and hydrate only the interactive components, each on its own schedule, with optional per-island code splitting.

v0.4.2 ESM-only MIT

It is a plugin on top of @sigx/server-renderer (installed automatically as a dependency). The base renderer hydrates the whole tree; islands lets you hydrate just the parts marked with client:* directives — everything else stays as cheap static HTML.

Why islands#

Most pages are mostly static. Hydrating the entire tree ships and runs JavaScript for content that never changes. With islands you opt in to interactivity per component:

  • A client:visible chart hydrates only when scrolled into view.
  • A client:idle widget waits for the browser to be idle.
  • The surrounding article ships zero client JS.

The three pieces#

Using islands always involves the same trio (from the package's own quick-start):

TypeScript
// 1. Server — register the plugin on your SSR instance
import { createSSR } from '@sigx/server-renderer';
import { islandsPlugin } from '@sigx/ssr-islands';

const ssr = createSSR().use(islandsPlugin());
const html = await ssr.render(<App />);
TypeScript
// 2. Client — register island components, then hydrate them
import { hydrateIslands, registerComponent } from '@sigx/ssr-islands';
import { Counter } from './components/Counter';

registerComponent('Counter', Counter);
hydrateIslands();
TSX
// 3. JSX types — enable the client:* attributes
import '@sigx/ssr-islands/jsx';

<Counter client:visible />
<Widget client:idle />

The server plugin intercepts components carrying a client:* directive, captures their signal state, and injects the __SIGX_ISLANDS__ hydration data. On the client, hydrateIslands() reads that data and schedules each island according to its strategy.

Hydration strategies#

DirectiveHydrates…
client:loadimmediately on page load
client:idleduring browser idle time (requestIdleCallback)
client:visiblewhen the element scrolls into view (IntersectionObserver)
client:mediawhen a media query matches (client:media="(min-width: 768px)")
client:onlymount fresh on the client — no SSR content rendered

See Client directives for the details of each.

Next steps#