newX 1.3: islands to disk, server-mode islands, and an image proxy→

Islands

Islands architecture

The server renders your full page as HTML, then only the pieces you mark as islands hydrate in the browser. Everything else ships zero JavaScript.

Why islands

A page full of interactive widgets doesn't need to ship one giant bundle. Each island is a small, self-contained hydration entry: it imports only what it needs, hydrates in place, and nothing on the page outside an island is ever re-rendered on the client. That keeps first paint fast and the JS budget predictable. The build step logs every island bundle it generates:

terminal · x build
$x build
[x] building island bundles...
[x] ✓ / LikeButton, SearchWidget
[x] ✓ /blog/[slug] LikeButton
[x] build complete in 1.1s -> .x

Creating an island

Wrap a component in <Island> and register it on the same page or layout with export const islands. Only registered islands get a hydration bundle, so an unregistered component never ships client JS even if you wrap it.

src/components/like-button.tsx
import { useState } from "react";export default function LikeButton() {  const [count, setCount] = useState(0);  return (    <button onClick={() => setCount((c) => c + 1)} className="rounded-full border px-4 py-2">      Like {count}    </button>  );}
src/pages/blog/[slug].tsx
import { Island } from "@thexjs/core";import { LikeButton } from "../../components/like-button";export const islands = { LikeButton };export default function BlogPost({ post }) {  return (    <article>      <h1 className="text-3xl font-bold">{post.title}</h1>      <div>{post.body}</div>      <Island name="LikeButton" client="visible">        <LikeButton /> >      </Island>    </article>  );}

Hydration triggers

The client prop picks when the island hydrates:

  • client="visible" hydrates when the island scrolls into view. Good for content below the fold.
  • client="idle" hydrates when the browser goes idle. Good for widgets the user isn't waiting on.
  • client="load" hydrates immediately on page load. Use for the first thing the user interacts with.

How hydration works

At build time X bundles each island separately, server-renders the page to static HTML with the island's markup inline, and drops in a small loader script. In the browser the loader fetches the island's chunk on demand and hydrates only that subtree. Islands can be nested and reused across routes; each registered component gets exactly one entry per route.