Router overview
An isomorphic router for ilha apps — synchronous HTML on the server, signal-driven SPA navigation in the browser.
@ilha/router is an isomorphic router for ilha apps: synchronous HTML on the server, signal-driven SPA navigation in the browser. It is a separate package from ilha, so you only add it when you need multi-page routing.
Every route is an ilha island. The router matches URLs, runs loaders, and mounts the active page. Route context (routePath, routeParams, and related signals) uses context(), so any island can read the current route without extra wiring.
Install
npm install @ilha/routerpnpm add @ilha/routeryarn add @ilha/routerbun add @ilha/routerImport paths
| Import path | Use it for |
|---|---|
@ilha/router |
Runtime router, loaders, navigation helpers, route context, and built-in islands. |
@ilha/router/vite |
Vite file-system routing plugin. |
@ilha/router/rspack |
Rspack file-system routing plugin. |
@ilha/router/rolldown |
Rolldown file-system routing plugin. |
@ilha/router/server-island |
Client proxy factory for server-defined islands (used by generated code). |
@ilha/router/ssr |
Production SSR endpoints middleware — POST /__ilha/frame and GET /__ilha/loader. |
@ilha/router/server-island-registry |
setFrameGuard(), setLoaderGuard(), setFrameAuth() — gate frame requests. |
Quick start
Client-side SPA
import { router } from "@ilha/router";
import {
HomePage,
AboutPage,
UserPage,
NotFound,
} from "./pages";
router()
.route("/", HomePage)
.route("/about", AboutPage)
.route("/user/:id", UserPage)
.route("/**", NotFound)
.mount("#app");
Server-side rendering
SSR is built into the SPA router — no separate server entry or render call. Add the SSR middleware and mark what runs on the server:
// vite.config.ts
import pages from "@ilha/router/vite";
import oxide from "oxidejs/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
oxide({ middleware: ["@ilha/router/ssr"] }),
pages(),
],
});
Selective: move a component into a *.server.ts(x) file, import it, and use it like any other element. Its markup renders on the server and stays live through frames:
// src/pages/index.tsx
import { TaskList } from "$lib/tasks.server";
export default ilha.render(() => <TaskList />);
Whole pages: rename src/pages/about.tsx to src/pages/about.server.tsx and the entire route renders server-side.
Details: Server islands, Server pages.
Where to go next
| Topic | Page |
|---|---|
| Routes, navigation, route context | Routes and navigation |
| Loaders and data fetching | Loaders |
| File-system routing with the plugin | File-system routing |
| SSR and manual rendering | Server rendering |
| Server islands and server pages | Server islands |
| Guards, origins, and security | Middleware and security |
| Production deployment | Deployment |
| Package symbol reference | Router reference |