Skip to content
Ilha
Esc
↑↓navigate↵open⌘Jpreview
On this page

Deployment

Host a router app in production — oxidejs SSR middleware, static prerendering, and where to register guards.

How you deploy depends on whether your app needs SSR/server islands or renders to static HTML.

SPA + SSR (server-rendered)

For file-system routing with oxidejs, the SSR middleware serves the internal frame endpoint in production — the route-graph imports are implicit:

// vite.config.ts
import const pages: (options?: IlhaPagesOptions) => Plugin
Vite plugin — use via `@ilha/router/vite`.
pages
from "@ilha/router/vite";
import const oxide: (options?: OxidejsOptions | undefined) => import("vite").Plugin<any>[] | import("vite").Plugin<any>oxide from "oxidejs/vite"; import { function defineConfig(config: UserConfig): UserConfig (+5 overloads)
Type helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
defineConfig
} from "vite";
export default function defineConfig(config: UserConfig): UserConfig (+5 overloads)
Type helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
defineConfig
({
UserConfig.plugins?: PluginOption[] | undefined
Array of vite plugins to use.
plugins
: [function oxide(options?: OxidejsOptions | undefined): import("vite").Plugin<any>[] | import("vite").Plugin<any>oxide({
OxidejsOptions.middleware?: (string | {
    module: string;
    imports?: string[];
})[] | undefined
Module specifiers whose default export is `(request, ctx) => Response | undefined | Promise<Response | undefined>`. Tried in order at the top of the production fetch handler; a Response short-circuits. Dev servers use connect middleware instead.
middleware
: ["@ilha/router/ssr"] }), function pages(options?: IlhaPagesOptions): Plugin
Vite plugin — use via `@ilha/router/vite`.
pages
()],
});

The @ilha/router/ssr middleware serves POST /__ilha/frame for server-island and server-page re-renders.

Any host that runs an oxidejs fetch handler serves it. See Server islands and Middleware and security.

If you host the router in your own fetch handler instead, use the manual render methods — render(), renderResponse(), or respond() — described in Server islands.

Registering guards in production

Deny-by-default means /__ilha/frame returns 403 until you install a guard. Call the guard once at server startup, before handling requests:

function setFrameGuard(guard: FrameGuard): void
Install a guard consulted by every `/__ilha/frame` request (dev middleware and the production `@ilha/router/ssr` handler share this slot — both read it from `globalThis`). Return a `Response` to reject; return nothing to allow. Island state is world-readable through frames unless you gate them, so apps serving private data should install a session check here.
setFrameGuard
((request: Requestrequest) =>
function isSignedIn(_request: Request): booleanisSignedIn(request: Requestrequest) ? var undefinedundefined : new var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response
The **`Response`** interface of the Fetch API represents the response to a request. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response)
Response
("Unauthorized", { ResponseInit.status?: number | undefinedstatus: 401 })
);

See Middleware and security for the full guard, origin, and CSRF model.

Static prerendering (MPA)

When you do not need runtime SSR or server islands, set mode: "static" in the plugin options. The generated client module then exports a registry of pages without a route graph. Prerender each route’s HTML at build time (for example with renderResponse), and mount the matching page from the registry:

import { mount } from "ilha";
import { registry } from "ilha:pages/client";

const host = document.querySelector<HTMLDivElement>("#app")!;
mount(host, registry["about"]);

Hash mode (setHistoryMode("hash")) is another static-host option when you cannot serve an SPA fallback for every URL. SSR + hydration is not supported in hash mode.

Topic Guide
Guards in production Middleware and security
Error handling Error boundaries
Plugin mode and virtual modules File-system routing

Was this page helpful?