@ilha/router 0.8.4 → 0.8.6

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/dist/index.d.ts CHANGED
@@ -65,6 +65,10 @@ export type Loader<T> = (ctx: LoaderContext) => Promise<T> | T;
65
65
  /**
66
66
  * Identity function for declaring a loader. Exists purely as a type anchor and
67
67
  * a marker for the Vite plugin to detect by export name.
68
+ *
69
+ * Loaders must read `ctx.params`/`ctx.url` rather than `useRoute()` — the
70
+ * route store still holds the previous route while a navigation's loader is
71
+ * in flight, so `useRoute().params()` inside a loader reads stale params.
68
72
  */
69
73
  export declare function loader<T>(fn: Loader<T>): Loader<T>;
70
74
  /** Extract the return type of a loader. */
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { A as wrapLayout, C as routePath, D as src_default, E as serializeHead, M as setHistoryMode, O as useRoute, S as routeParams, T as router, _ as navigating, a as RouterView, b as redirect, c as composeLoaders, d as error, f as head, g as navigate, h as loader, i as RouterLink, j as getHistoryMode, k as wrapError, l as defineLayout, m as isActive, n as LoaderError, o as afterNavigate, p as invalidate, r as Redirect, s as beforeNavigate, t as LOADER_ENDPOINT, u as enableLinkInterception, v as prefetch, w as routeSearch, x as routeHash, y as prime } from "./src-BFzs4FwW.js";
1
+ import { A as wrapLayout, C as routePath, D as src_default, E as serializeHead, M as setHistoryMode, O as useRoute, S as routeParams, T as router, _ as navigating, a as RouterView, b as redirect, c as composeLoaders, d as error, f as head, g as navigate, h as loader, i as RouterLink, j as getHistoryMode, k as wrapError, l as defineLayout, m as isActive, n as LoaderError, o as afterNavigate, p as invalidate, r as Redirect, s as beforeNavigate, t as LOADER_ENDPOINT, u as enableLinkInterception, v as prefetch, w as routeSearch, x as routeHash, y as prime } from "./src-_T1q_MN5.js";
2
2
 
3
3
  export { LOADER_ENDPOINT, LoaderError, Redirect, RouterLink, RouterView, afterNavigate, beforeNavigate, composeLoaders, src_default as default, defineLayout, enableLinkInterception, error, getHistoryMode, head, invalidate, isActive, loader, navigate, navigating, prefetch, prime, redirect, routeHash, routeParams, routePath, routeSearch, router, serializeHead, setHistoryMode, useRoute, wrapError, wrapLayout };
@@ -136,6 +136,10 @@ const isBrowser = typeof window !== "undefined" && typeof document !== "undefine
136
136
  /**
137
137
  * Identity function for declaring a loader. Exists purely as a type anchor and
138
138
  * a marker for the Vite plugin to detect by export name.
139
+ *
140
+ * Loaders must read `ctx.params`/`ctx.url` rather than `useRoute()` — the
141
+ * route store still holds the previous route while a navigation's loader is
142
+ * in flight, so `useRoute().params()` inside a loader reads stale params.
139
143
  */
140
144
  function loader(fn) {
141
145
  return fn;
@@ -183,6 +187,7 @@ function composeLoaders(loaders) {
183
187
  }
184
188
  const WRAP_LAYOUT_LEAF = Symbol.for("ilha.router.wrapLayout.leaf");
185
189
  const WRAP_LAYOUT_HANDLER = Symbol.for("ilha.router.wrapLayout.handler");
190
+ const ISLAND_CALL = Symbol.for("ilha.islandCall");
186
191
  function extractHydratableInnerHtml(block) {
187
192
  const m = block.match(/^<([a-zA-Z][\w-]*)\s[^>]*>([\s\S]*)<\/\1>\s*$/);
188
193
  return m ? m[2] : block;
@@ -315,6 +320,7 @@ function layoutHtmlWithEmptyKPage(wrappedLayout, props) {
315
320
  ...partial ?? {}
316
321
  }));
317
322
  Object.assign(shellChild, { toString: () => "" });
323
+ shellChild[ISLAND_CALL] = true;
318
324
  return handler(shellChild).toString(props);
319
325
  }
320
326
  async function wrapLayoutSlotMarkup(innerWrapped, leafPage, props, opts) {
@@ -334,6 +340,7 @@ function wrapLayout(layout, page) {
334
340
  } : props);
335
341
  });
336
342
  Object.assign(KeyedPage, { toString: page.toString.bind(page) });
343
+ KeyedPage[ISLAND_CALL] = true;
337
344
  const Wrapped = layout(KeyedPage);
338
345
  Wrapped[WRAP_LAYOUT_LEAF] = leafPage;
339
346
  Wrapped[WRAP_LAYOUT_HANDLER] = layout;
@@ -1531,11 +1538,13 @@ function router(options = {}) {
1531
1538
  if (getHistoryMode() === "hash") console.warn("[ilha-router] mount({ hydrate: true }) was called in hash mode. SSR + hydration assumes the server can render the active route, but in hash mode the server only ever sees the document URL. Use plain SPA mode (`mount(target)` without `hydrate: true`) for hash-mode apps.");
1532
1539
  const viewHost = host.querySelector("[data-router-view]") ?? host;
1533
1540
  let currentMountedIsland = activeIsland();
1541
+ let currentMountedPath = routePath() + routeSearch();
1534
1542
  const reverseRegistry = registry ? buildReverseRegistry(registry) : void 0;
1535
1543
  let navVersion = 0;
1536
1544
  const NavHandler = ilha.render(() => {
1537
1545
  const current = activeIsland();
1538
- if (current !== currentMountedIsland) {
1546
+ const pathWithSearch = routePath() + routeSearch();
1547
+ if (current !== currentMountedIsland || pathWithSearch !== currentMountedPath) {
1539
1548
  const thisNav = ++navVersion;
1540
1549
  navAbort?.abort();
1541
1550
  navAbort = new AbortController();
@@ -1546,8 +1555,7 @@ function router(options = {}) {
1546
1555
  unmountView?.();
1547
1556
  unmountView = null;
1548
1557
  try {
1549
- const loc = getAdapter().readLocation();
1550
- unmountView = await mountRouteWithHydration(current, viewHost, loc.pathname + loc.search, signal, registry, reverseRegistry);
1558
+ unmountView = await mountRouteWithHydration(current, viewHost, pathWithSearch, signal, registry, reverseRegistry);
1551
1559
  } catch (e) {
1552
1560
  if (e?.name === "AbortError") return;
1553
1561
  console.error("[ilha-router] navigation failed:", e);
@@ -1557,6 +1565,7 @@ function router(options = {}) {
1557
1565
  settle();
1558
1566
  }
1559
1567
  currentMountedIsland = current;
1568
+ currentMountedPath = pathWithSearch;
1560
1569
  });
1561
1570
  }
1562
1571
  return "";
@@ -1604,11 +1613,13 @@ function router(options = {}) {
1604
1613
  const settle = beginNavigation();
1605
1614
  try {
1606
1615
  const loc = getAdapter().readLocation();
1607
- const um = await mountRouteWithHydration(island, viewHost, loc.pathname + loc.search, ac.signal, registry, reverseRegistry);
1616
+ const pathWithSearch = loc.pathname + loc.search;
1617
+ const um = await mountRouteWithHydration(island, viewHost, pathWithSearch, ac.signal, registry, reverseRegistry);
1608
1618
  if (thisNav === navVersion) {
1609
1619
  unmountView?.();
1610
1620
  unmountView = um;
1611
1621
  currentMountedIsland = island;
1622
+ currentMountedPath = pathWithSearch;
1612
1623
  } else um();
1613
1624
  } catch (e) {
1614
1625
  if (e?.name !== "AbortError") console.error("[ilha-router] invalidate failed:", e);
@@ -1633,6 +1644,7 @@ function router(options = {}) {
1633
1644
  }
1634
1645
  let unmountIsland = null;
1635
1646
  let currentMountedIsland = null;
1647
+ let currentMountedPath = null;
1636
1648
  let navVersion = 0;
1637
1649
  unmountView = RouterView.mount(host);
1638
1650
  /**
@@ -1644,6 +1656,7 @@ function router(options = {}) {
1644
1656
  unmountIsland?.();
1645
1657
  unmountIsland = null;
1646
1658
  currentMountedIsland = island;
1659
+ currentMountedPath = routePath() + routeSearch();
1647
1660
  if (!island) {
1648
1661
  const nfHost = host?.querySelector("[data-router-not-found]");
1649
1662
  if (_notFound && nfHost) unmountIsland = _notFound.mount(nfHost);
@@ -1690,7 +1703,8 @@ function router(options = {}) {
1690
1703
  });
1691
1704
  const NavHandler = ilha.render(() => {
1692
1705
  const current = activeIsland();
1693
- if (current !== currentMountedIsland) {
1706
+ const pathWithSearch = routePath() + routeSearch();
1707
+ if (current !== currentMountedIsland || pathWithSearch !== currentMountedPath) {
1694
1708
  const thisNav = ++navVersion;
1695
1709
  navAbort?.abort();
1696
1710
  navAbort = new AbortController();
package/dist/ssr.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as LOADER_ENDPOINT } from "./src-BFzs4FwW.js";
1
+ import { t as LOADER_ENDPOINT } from "./src-_T1q_MN5.js";
2
2
  import { pageRouter, registry } from "ilha:pages/server";
3
3
  import "ilha:loaders";
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ilha/router",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "description": "A tiny SPA router for Ilha",
5
5
  "keywords": [
6
6
  "frontend",