@solidjs/router 2.0.0-next.17 → 2.0.0-next.19

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.
@@ -1,5 +1,5 @@
1
1
  /*@refresh skip*/
2
- import { createMemo, createRoot, getOwner, onCleanup, runWithOwner, untrack } from "solid-js";
2
+ import { createMemo, createRoot, getOwner, onCleanup, runWithOwner, untrack, Show } from "solid-js";
3
3
  import { getRequestEvent, isServer } from "@solidjs/web";
4
4
  import { createRouteContext, getIntent, getRouteMatches, resolveLazySubtree, RouteContextObj, setInPreloadFn, unresolvedLazyMatches } from "../routing.js";
5
5
  export function Root(props) {
@@ -104,13 +104,17 @@ export function Routes(props) {
104
104
  return <>{outlet()}</>;
105
105
  }
106
106
  const createOutlet = (child) => {
107
- return () => {
108
- const c = child();
109
- if (c) {
110
- return <RouteContextObj value={c}>{c.outlet()}</RouteContextObj>;
111
- }
112
- return undefined;
113
- };
107
+ // Keyed on the context's identity (#588). `when` compiles to a lazy prop
108
+ // getter, so child() is tracked inside Show's memo — the outlet function
109
+ // reads nothing reactive and Show owns the subtree. Levels whose context is
110
+ // reference-reused (parent layouts) keep their subtree across navigations;
111
+ // a changed context must re-create the provider, not just re-render under
112
+ // it: a context value is registered once at provider creation
113
+ // (setContext(provider, props.value)), so non-keyed reuse would leave new
114
+ // route content reading the previous level's context.
115
+ return () => (<Show when={child()} keyed>
116
+ {c => <RouteContextObj value={c}>{c.outlet()}</RouteContextObj>}
117
+ </Show>);
114
118
  };
115
119
  // for data only mode with single flight mutations
116
120
  function dataOnly(event, routerState, branches) {
package/dist/routing.js CHANGED
@@ -5,6 +5,7 @@ import { DEV } from "solid-js";
5
5
  import { createComponent, createContext, createMemo, createSignal, isPending, NotReadyError, untrack, useContext } from "solid-js";
6
6
  import { clearFlashCookie, getRequestEvent, hasFlashCookie, isServer } from "@solidjs/web";
7
7
  import { mockBase, comparablePath, createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils.js";
8
+ import { HREF } from "./paths.js";
8
9
  const MAX_REDIRECTS = 100;
9
10
  /** Consider this API opaque and internal. It is likely to change in the future. */
10
11
  export const RouterContextObj = createContext();
@@ -262,15 +263,20 @@ const encodeSegment = (s) => encodeURIComponent(s).replace(/%(2B|40|3A|24|26|2C|
262
263
  const lazyBoundaries = new WeakMap();
263
264
  // Module scope: boundary resolution is global, deterministic state (same
264
265
  // thunk -> same routes), shared by every factory instance and the server's
265
- // flight collector.
266
+ // flight collector. The counter is the source of truth; the client mirrors
267
+ // it into a signal for subscription. Server render is pure (signal writes
268
+ // are inert as of solid 2.0.0-rc.3): there the plain counter serves reads,
269
+ // and re-runs come from the parked computation's promise retry, not from
270
+ // reactivity.
271
+ let lazyTreeCounter = 0;
266
272
  const [lazyTreeVersion, setLazyTreeVersion] = createSignal(0);
267
273
  /** Reactive read of the lazy-subtree version — recompile compiled branches when it changes. */
268
274
  export function trackLazySubtrees() {
269
- return lazyTreeVersion();
275
+ return isServer ? lazyTreeCounter : lazyTreeVersion();
270
276
  }
271
277
  /** Non-reactive read, for cache-busting outside the reactive graph (server collectors). */
272
278
  export function peekLazySubtrees() {
273
- return untrack(lazyTreeVersion);
279
+ return lazyTreeCounter;
274
280
  }
275
281
  function getLazyBoundary(thunk) {
276
282
  let record = lazyBoundaries.get(thunk);
@@ -314,7 +320,8 @@ export function resolveLazySubtree(record) {
314
320
  m.routes ||
315
321
  [];
316
322
  record.resolved = routes;
317
- setLazyTreeVersion(v => v + 1);
323
+ lazyTreeCounter++;
324
+ isServer || setLazyTreeVersion(lazyTreeCounter);
318
325
  return record.resolved;
319
326
  }, e => {
320
327
  // ?? Error(): a held undefined would read as "no failure" and refire
@@ -694,9 +701,20 @@ export function createRouterContext(integration, branches, getContext, options =
694
701
  }
695
702
  return;
696
703
  }
697
- // typed path proxy nodes coerce to their href
704
+ // A paths node carries its logical path under the Href brand — read
705
+ // that rather than coercing: toString() renders the *display* href
706
+ // (eg. hash mode's `#` prefix), which is for the DOM, not for routing.
707
+ // Foreign Href-branded values without the slot still coerce.
698
708
  if (typeof to !== "string")
699
- to = to.toString();
709
+ to = to[HREF] || to.toString();
710
+ // Display hrefs can still arrive as plain strings: terminating paths
711
+ // calls type as `string`, and redirect Location headers round-trip
712
+ // through here. Under hash mode those start with `#` — a spelling no
713
+ // logical path uses — so map them back through the integration's
714
+ // parser, exactly like the anchor click handler does. Elsewhere
715
+ // parsePath is identity and `#...` keeps its URL meaning below.
716
+ if (to[0] === "#")
717
+ to = parsePath(to);
700
718
  const { replace, resolve, scroll, state: nextState } = {
701
719
  replace: false,
702
720
  resolve: true,
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "2.0.0-next.17",
9
+ "version": "2.0.0-next.19",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",
@@ -37,22 +37,22 @@
37
37
  "@rollup/plugin-babel": "6.0.4",
38
38
  "@rollup/plugin-node-resolve": "15.3.0",
39
39
  "@rollup/plugin-terser": "0.4.4",
40
- "@solidjs/vite-plugin": "3.0.0-next.28",
41
- "@solidjs/web": "^2.0.0-rc.1",
40
+ "@solidjs/vite-plugin": "3.0.0-next.35",
41
+ "@solidjs/web": "^2.0.0-rc.4",
42
42
  "@types/jest": "^29.5.14",
43
43
  "@types/node": "^22.10.0",
44
- "babel-preset-solid": "^2.0.0-rc.1",
44
+ "babel-preset-solid": "^2.0.0-rc.2",
45
45
  "jsdom": "^25.0.1",
46
46
  "prettier": "^3.4.1",
47
47
  "rollup": "^4.27.4",
48
- "solid-js": "^2.0.0-rc.1",
48
+ "solid-js": "^2.0.0-rc.4",
49
49
  "typescript": "^5.7.2",
50
- "vite": "^6.0.0",
51
- "vitest": "^2.1.6"
50
+ "vite": "^8.2.2",
51
+ "vitest": "^4.1.11"
52
52
  },
53
53
  "peerDependencies": {
54
- "@solidjs/web": "^2.0.0-rc.1",
55
- "solid-js": "^2.0.0-rc.1"
54
+ "@solidjs/web": "^2.0.0-rc.4",
55
+ "solid-js": "^2.0.0-rc.4"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "rm -rf dist && tsc && rollup -c",