@ilha/router 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -666,6 +666,11 @@ interface HydrateOptions {
666
666
  }
667
667
 
668
668
  type HistoryMode = "history" | "hash";
669
+ type RouterMode = "spa" | "mpa";
670
+
671
+ interface RouterOptions {
672
+ mode?: RouterMode; // default: "spa"
673
+ }
669
674
 
670
675
  // Helper — returns fn as-is with LayoutHandler type enforced
671
676
  function defineLayout(fn: LayoutHandler): LayoutHandler;
@@ -927,6 +932,18 @@ pageRouter.hydrate(registry);
927
932
  pages({
928
933
  dir: "src/pages", // pages directory (default: "src/pages")
929
934
  generated: ".ilha/routes.ts", // generated file output (default: ".ilha/routes.ts")
935
+ mode: "spa", // "spa" | "mpa" (default: "spa")
936
+ });
937
+ ```
938
+
939
+ Use `mode: "mpa"` when you want filesystem-routed pages to behave like a multi-page app: the current page can still be SSR-rendered and hydrated, but in-app links are not intercepted by the router, so navigation is handled by the browser as a full document request.
940
+
941
+ ```ts
942
+ // vite.config.ts
943
+ import { pages } from "@ilha/router/vite";
944
+
945
+ export default defineConfig({
946
+ plugins: [pages({ mode: "mpa" })],
930
947
  });
931
948
  ```
932
949
 
@@ -90,6 +90,16 @@ declare function defineLayout(layout: LayoutHandler): LayoutHandler;
90
90
  interface NavigateOptions {
91
91
  replace?: boolean;
92
92
  }
93
+ type RouterMode = "spa" | "mpa";
94
+ interface RouterOptions {
95
+ /**
96
+ * Client navigation mode. `spa` intercepts in-app links and renders routes
97
+ * in-place. `mpa` leaves links to the browser, so each page navigation is a
98
+ * full document request while still allowing hydration of the current route.
99
+ * Default: `spa`.
100
+ */
101
+ mode?: RouterMode;
102
+ }
93
103
  interface HydratableRenderOptions extends Partial<Omit<HydratableOptions, "name">> {}
94
104
  interface HydrateOptions {
95
105
  root?: Element;
@@ -234,7 +244,7 @@ declare function enableLinkInterception(root?: Element | Document, options?: Lin
234
244
  declare const RouterView: Island<Record<string, unknown>, Record<never, never>>;
235
245
  declare const RouterLink: Island<Record<string, unknown>, Omit<Omit<Record<never, never>, K> & Record<"href", string>, "label"> & Record<"label", string>>;
236
246
  declare function isActive(pattern: string): boolean;
237
- declare function router(): RouterBuilder;
247
+ declare function router(options?: RouterOptions): RouterBuilder;
238
248
  declare const _default: {
239
249
  router: typeof router;
240
250
  navigate: typeof navigate;
@@ -251,4 +261,4 @@ declare const _default: {
251
261
  composeLoaders: typeof composeLoaders;
252
262
  };
253
263
  //#endregion
254
- export { prefetch as A, wrapLayout as B, composeLoaders as C, isActive as D, error as E, routePath as F, getHistoryMode as H, routeSearch as I, router as L, redirect as M, routeHash as N, loader as O, routeParams as P, useRoute as R, _default as S, enableLinkInterception as T, setHistoryMode as U, HistoryMode as V, RouteRecord as _, InferLoader as a, RouterLink as b, LinkInterceptionOptions as c, LoaderError as d, MergeLoaders as f, RenderResponse as g, Redirect as h, HydrateOptions as i, prime as j, navigate as k, Loader as l, NavigateOptions as m, ErrorHandler as n, LOADER_ENDPOINT as o, MountOptions as p, HydratableRenderOptions as r, LayoutHandler as s, AppError as t, LoaderContext as u, RouteSnapshot as v, defineLayout as w, RouterView as x, RouterBuilder as y, wrapError as z };
264
+ export { loader as A, useRoute as B, RouterView as C, enableLinkInterception as D, defineLayout as E, routeHash as F, setHistoryMode as G, wrapLayout as H, routeParams as I, routePath as L, prefetch as M, prime as N, error as O, redirect as P, routeSearch as R, RouterOptions as S, composeLoaders as T, HistoryMode as U, wrapError as V, getHistoryMode as W, RouteRecord as _, InferLoader as a, RouterLink as b, LinkInterceptionOptions as c, LoaderError as d, MergeLoaders as f, RenderResponse as g, Redirect as h, HydrateOptions as i, navigate as j, isActive as k, Loader as l, NavigateOptions as m, ErrorHandler as n, LOADER_ENDPOINT as o, MountOptions as p, HydratableRenderOptions as r, LayoutHandler as s, AppError as t, LoaderContext as u, RouteSnapshot as v, _default as w, RouterMode as x, RouterBuilder as y, router as z };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as prefetch, B as wrapLayout, C as composeLoaders, D as isActive, E as error, F as routePath, H as getHistoryMode, I as routeSearch, L as router, M as redirect, N as routeHash, O as loader, P as routeParams, R as useRoute, S as _default, T as enableLinkInterception, U as setHistoryMode, V as HistoryMode, _ as RouteRecord, a as InferLoader, b as RouterLink, c as LinkInterceptionOptions, d as LoaderError, f as MergeLoaders, g as RenderResponse, h as Redirect, i as HydrateOptions, j as prime, k as navigate, l as Loader, m as NavigateOptions, n as ErrorHandler, o as LOADER_ENDPOINT, p as MountOptions, r as HydratableRenderOptions, s as LayoutHandler, t as AppError, u as LoaderContext, v as RouteSnapshot, w as defineLayout, x as RouterView, y as RouterBuilder, z as wrapError } from "./index-CFBKeDvv.js";
2
- export { AppError, ErrorHandler, HistoryMode, HydratableRenderOptions, HydrateOptions, InferLoader, LOADER_ENDPOINT, LayoutHandler, LinkInterceptionOptions, Loader, LoaderContext, LoaderError, MergeLoaders, MountOptions, NavigateOptions, Redirect, RenderResponse, RouteRecord, RouteSnapshot, RouterBuilder, RouterLink, RouterView, composeLoaders, _default as default, defineLayout, enableLinkInterception, error, getHistoryMode, isActive, loader, navigate, prefetch, prime, redirect, routeHash, routeParams, routePath, routeSearch, router, setHistoryMode, useRoute, wrapError, wrapLayout };
1
+ import { A as loader, B as useRoute, C as RouterView, D as enableLinkInterception, E as defineLayout, F as routeHash, G as setHistoryMode, H as wrapLayout, I as routeParams, L as routePath, M as prefetch, N as prime, O as error, P as redirect, R as routeSearch, S as RouterOptions, T as composeLoaders, U as HistoryMode, V as wrapError, W as getHistoryMode, _ as RouteRecord, a as InferLoader, b as RouterLink, c as LinkInterceptionOptions, d as LoaderError, f as MergeLoaders, g as RenderResponse, h as Redirect, i as HydrateOptions, j as navigate, k as isActive, l as Loader, m as NavigateOptions, n as ErrorHandler, o as LOADER_ENDPOINT, p as MountOptions, r as HydratableRenderOptions, s as LayoutHandler, t as AppError, u as LoaderContext, v as RouteSnapshot, w as _default, x as RouterMode, y as RouterBuilder, z as router } from "./index-DSE6uoR1.js";
2
+ export { AppError, ErrorHandler, HistoryMode, HydratableRenderOptions, HydrateOptions, InferLoader, LOADER_ENDPOINT, LayoutHandler, LinkInterceptionOptions, Loader, LoaderContext, LoaderError, MergeLoaders, MountOptions, NavigateOptions, Redirect, RenderResponse, RouteRecord, RouteSnapshot, RouterBuilder, RouterLink, RouterMode, RouterOptions, RouterView, composeLoaders, _default as default, defineLayout, enableLinkInterception, error, getHistoryMode, isActive, loader, navigate, prefetch, prime, redirect, routeHash, routeParams, routePath, routeSearch, router, setHistoryMode, useRoute, wrapError, wrapLayout };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { C as wrapError, E as setHistoryMode, S as useRoute, T as getHistoryMode, _ as routeParams, a as RouterView, b as router, c as enableLinkInterception, d as loader, f as navigate, g as routeHash, h as redirect, i as RouterLink, l as error, m as prime, n as LoaderError, o as composeLoaders, p as prefetch, r as Redirect, s as defineLayout, t as LOADER_ENDPOINT, u as isActive, v as routePath, w as wrapLayout, x as src_default, y as routeSearch } from "./src-0cb8FYdn.js";
1
+ import { C as wrapError, E as setHistoryMode, S as useRoute, T as getHistoryMode, _ as routeParams, a as RouterView, b as router, c as enableLinkInterception, d as loader, f as navigate, g as routeHash, h as redirect, i as RouterLink, l as error, m as prime, n as LoaderError, o as composeLoaders, p as prefetch, r as Redirect, s as defineLayout, t as LOADER_ENDPOINT, u as isActive, v as routePath, w as wrapLayout, x as src_default, y as routeSearch } from "./src-DX07qe2S.js";
2
2
  export { LOADER_ENDPOINT, LoaderError, Redirect, RouterLink, RouterView, composeLoaders, src_default as default, defineLayout, enableLinkInterception, error, getHistoryMode, isActive, loader, navigate, prefetch, prime, redirect, routeHash, routeParams, routePath, routeSearch, router, setHistoryMode, useRoute, wrapError, wrapLayout };
@@ -138,7 +138,8 @@ function validateEntries(entries, pagesDir) {
138
138
  else seenNames.set(entry.name, entry.file);
139
139
  }
140
140
  }
141
- async function generate(pagesDir, outFile) {
141
+ async function generate(pagesDir, outFile, options = {}) {
142
+ const mode = options.mode ?? "spa";
142
143
  const entries = sortEntries(await scanPages(pagesDir));
143
144
  validateEntries(entries, pagesDir);
144
145
  const rel = (abs) => {
@@ -174,7 +175,7 @@ async function generate(pagesDir, outFile) {
174
175
  ...registryLines,
175
176
  `};`,
176
177
  ``,
177
- `export const pageRouter = router()`,
178
+ `export const pageRouter = router(${mode === "mpa" ? `{ mode: "mpa" }` : ""})`,
178
179
  ...routeLines,
179
180
  ` ;`
180
181
  ].join("\n");
@@ -285,7 +286,7 @@ function createPagesPluginState(options) {
285
286
  };
286
287
  const regen = async () => {
287
288
  try {
288
- await generate(pagesDir, outFile);
289
+ await generate(pagesDir, outFile, { mode: options.mode });
289
290
  } catch (e) {
290
291
  console.error("[ilha:pages] codegen failed:", e);
291
292
  }
@@ -1,11 +1,20 @@
1
1
  import * as _$unplugin from "unplugin";
2
2
 
3
+ //#region src/codegen.d.ts
4
+ type PagesMode = "spa" | "mpa";
5
+ //#endregion
3
6
  //#region src/plugin.d.ts
4
7
  interface IlhaPagesOptions {
5
8
  /** Directory containing page files. Default: `src/pages` */
6
9
  dir?: string;
7
10
  /** Output path for the generated routes + registry file. Default: `.ilha/routes.ts` */
8
11
  generated?: string;
12
+ /**
13
+ * File-system router navigation mode. `spa` intercepts in-app links and
14
+ * renders routes client-side; `mpa` leaves links to the browser for full
15
+ * document navigations. Default: `spa`.
16
+ */
17
+ mode?: PagesMode;
9
18
  }
10
19
  declare const ilhaPages: _$unplugin.UnpluginInstance<IlhaPagesOptions | undefined, boolean>;
11
20
  //#endregion
@@ -1,5 +1,5 @@
1
- import { B as wrapLayout, n as ErrorHandler, s as LayoutHandler, t as AppError, v as RouteSnapshot, z as wrapError } from "./index-CFBKeDvv.js";
2
- import { n as ilhaPages, t as IlhaPagesOptions } from "./plugin-CnS_mBUE.js";
1
+ import { H as wrapLayout, V as wrapError, n as ErrorHandler, s as LayoutHandler, t as AppError, v as RouteSnapshot } from "./index-DSE6uoR1.js";
2
+ import { n as ilhaPages, t as IlhaPagesOptions } from "./plugin-Diq1AxSa.js";
3
3
  import * as _$unplugin from "unplugin";
4
4
 
5
5
  //#region src/rolldown.d.ts
package/dist/rolldown.js CHANGED
@@ -1,5 +1,5 @@
1
- import { C as wrapError, w as wrapLayout } from "./src-0cb8FYdn.js";
2
- import { t as ilhaPages } from "./plugin-DAk44om0.js";
1
+ import { C as wrapError, w as wrapLayout } from "./src-DX07qe2S.js";
2
+ import { t as ilhaPages } from "./plugin-Bhbl9aqc.js";
3
3
  //#region src/rolldown.ts
4
4
  /** Rolldown plugin — use via `@ilha/router/rolldown`. */
5
5
  function pages(options = {}) {
package/dist/rspack.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as wrapLayout, n as ErrorHandler, s as LayoutHandler, t as AppError, v as RouteSnapshot, z as wrapError } from "./index-CFBKeDvv.js";
2
- import { n as ilhaPages, t as IlhaPagesOptions } from "./plugin-CnS_mBUE.js";
1
+ import { H as wrapLayout, V as wrapError, n as ErrorHandler, s as LayoutHandler, t as AppError, v as RouteSnapshot } from "./index-DSE6uoR1.js";
2
+ import { n as ilhaPages, t as IlhaPagesOptions } from "./plugin-Diq1AxSa.js";
3
3
  import * as _$unplugin from "unplugin";
4
4
 
5
5
  //#region src/rspack.d.ts
package/dist/rspack.js CHANGED
@@ -1,5 +1,5 @@
1
- import { C as wrapError, w as wrapLayout } from "./src-0cb8FYdn.js";
2
- import { t as ilhaPages } from "./plugin-DAk44om0.js";
1
+ import { C as wrapError, w as wrapLayout } from "./src-DX07qe2S.js";
2
+ import { t as ilhaPages } from "./plugin-Bhbl9aqc.js";
3
3
  //#region src/rspack.ts
4
4
  /** Rspack plugin — use via `@ilha/router/rspack`. */
5
5
  function pages(options = {}) {
@@ -577,7 +577,8 @@ async function executeLoader(loader, url, params, request, signal) {
577
577
  };
578
578
  }
579
579
  }
580
- function router() {
580
+ function router(options = {}) {
581
+ const mode = options.mode ?? "spa";
581
582
  _records = [];
582
583
  _rou3 = createRouter();
583
584
  _islandToPattern = /* @__PURE__ */ new Map();
@@ -628,7 +629,7 @@ function router() {
628
629
  syncRouteFromLocation();
629
630
  const popHandler = () => syncRouteFromLocation();
630
631
  _navChangeCleanup = getAdapter().onChange(popHandler);
631
- _linkCleanup = enableLinkInterception(document);
632
+ _linkCleanup = mode === "spa" ? enableLinkInterception(document) : null;
632
633
  let unmountView = null;
633
634
  let navAbort = null;
634
635
  if (hydrate) {
package/dist/vite.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import { B as wrapLayout, n as ErrorHandler, s as LayoutHandler, t as AppError, v as RouteSnapshot, z as wrapError } from "./index-CFBKeDvv.js";
3
- import { n as ilhaPages, t as IlhaPagesOptions } from "./plugin-CnS_mBUE.js";
2
+ import { H as wrapLayout, V as wrapError, n as ErrorHandler, s as LayoutHandler, t as AppError, v as RouteSnapshot } from "./index-DSE6uoR1.js";
3
+ import { n as ilhaPages, t as IlhaPagesOptions } from "./plugin-Diq1AxSa.js";
4
4
  import * as fs from "node:fs";
5
5
  import * as http from "node:http";
6
6
  import { Agent, ClientRequest, ClientRequestArgs, OutgoingHttpHeaders } from "node:http";
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
- import { C as wrapError, w as wrapLayout } from "./src-0cb8FYdn.js";
2
- import { t as ilhaPages } from "./plugin-DAk44om0.js";
1
+ import { C as wrapError, w as wrapLayout } from "./src-DX07qe2S.js";
2
+ import { t as ilhaPages } from "./plugin-Bhbl9aqc.js";
3
3
  //#region src/vite.ts
4
4
  /** Vite plugin — use via `@ilha/router/vite`. */
5
5
  function pages(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ilha/router",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "A tiny SPA router for Ilha",
5
5
  "license": "MIT",
6
6
  "author": "Ryuz <ryuzer@proton.me>",