@tanstack/router-core 1.131.3 → 1.131.4

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,16 +1,14 @@
1
1
  import invariant from "tiny-invariant";
2
2
  import { batch } from "@tanstack/store";
3
3
  import { createControlledPromise } from "../utils.js";
4
- function hydrateMatch(deyhydratedMatch) {
5
- return {
6
- id: deyhydratedMatch.i,
7
- __beforeLoadContext: deyhydratedMatch.b,
8
- loaderData: deyhydratedMatch.l,
9
- status: deyhydratedMatch.s,
10
- ssr: deyhydratedMatch.ssr,
11
- updatedAt: deyhydratedMatch.u,
12
- error: deyhydratedMatch.e
13
- };
4
+ function hydrateMatch(match, deyhydratedMatch) {
5
+ match.id = deyhydratedMatch.i;
6
+ match.__beforeLoadContext = deyhydratedMatch.b;
7
+ match.loaderData = deyhydratedMatch.l;
8
+ match.status = deyhydratedMatch.s;
9
+ match.ssr = deyhydratedMatch.ssr;
10
+ match.updatedAt = deyhydratedMatch.u;
11
+ match.error = deyhydratedMatch.e;
14
12
  }
15
13
  async function hydrate(router) {
16
14
  var _a, _b, _c;
@@ -34,15 +32,17 @@ async function hydrate(router) {
34
32
  const pendingMinMs = route.options.pendingMinMs ?? router.options.defaultPendingMinMs;
35
33
  if (pendingMinMs) {
36
34
  const minPendingPromise = createControlledPromise();
37
- match.minPendingPromise = minPendingPromise;
35
+ match._nonReactive.minPendingPromise = minPendingPromise;
38
36
  match._forcePending = true;
39
37
  setTimeout(() => {
40
38
  minPendingPromise.resolve();
41
- router.updateMatch(match.id, (prev) => ({
42
- ...prev,
43
- minPendingPromise: void 0,
44
- _forcePending: void 0
45
- }));
39
+ router.updateMatch(match.id, (prev) => {
40
+ prev._nonReactive.minPendingPromise = void 0;
41
+ return {
42
+ ...prev,
43
+ _forcePending: void 0
44
+ };
45
+ });
46
46
  }, pendingMinMs);
47
47
  }
48
48
  }
@@ -52,15 +52,12 @@ async function hydrate(router) {
52
52
  (d) => d.i === match.id
53
53
  );
54
54
  if (!dehydratedMatch) {
55
- Object.assign(match, { dehydrated: false, ssr: false });
55
+ match._nonReactive.dehydrated = false;
56
+ match.ssr = false;
56
57
  return;
57
58
  }
58
- Object.assign(match, hydrateMatch(dehydratedMatch));
59
- if (match.ssr === false) {
60
- match._dehydrated = false;
61
- } else {
62
- match._dehydrated = true;
63
- }
59
+ hydrateMatch(match, dehydratedMatch);
60
+ match._nonReactive.dehydrated = match.ssr !== false;
64
61
  if (match.ssr === "data-only" || match.ssr === false) {
65
62
  if (firstNonSsrMatchIndex === void 0) {
66
63
  firstNonSsrMatchIndex = match.index;
@@ -118,7 +115,7 @@ async function hydrate(router) {
118
115
  const hasSsrFalseMatches = matches.some((m) => m.ssr === false);
119
116
  if (!hasSsrFalseMatches && !isSpaMode) {
120
117
  matches.forEach((match) => {
121
- match._dehydrated = void 0;
118
+ match._nonReactive.dehydrated = void 0;
122
119
  });
123
120
  return routeChunkPromise;
124
121
  }
@@ -133,7 +130,7 @@ async function hydrate(router) {
133
130
  );
134
131
  setMatchForcePending(match);
135
132
  match._displayPending = true;
136
- match.displayPendingPromise = loadPromise;
133
+ match._nonReactive.displayPendingPromise = loadPromise;
137
134
  loadPromise.then(() => {
138
135
  batch(() => {
139
136
  if (router.__store.state.status === "pending") {
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-client.js","sources":["../../../src/ssr/ssr-client.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport { batch } from '@tanstack/store'\nimport { createControlledPromise } from '../utils'\nimport type { AnyRouteMatch, MakeRouteMatch } from '../Matches'\nimport type { AnyRouter } from '../router'\nimport type { Manifest } from '../manifest'\nimport type { RouteContextOptions } from '../route'\nimport type { GLOBAL_TSR } from './ssr-server'\n\ndeclare global {\n interface Window {\n [GLOBAL_TSR]?: TsrSsrGlobal\n }\n}\n\nexport interface TsrSsrGlobal {\n router?: DehydratedRouter\n // clean scripts, shortened since this is sent for each streamed script\n c: () => void\n}\n\nfunction hydrateMatch(\n deyhydratedMatch: DehydratedMatch,\n): Partial<MakeRouteMatch> {\n return {\n id: deyhydratedMatch.i,\n __beforeLoadContext: deyhydratedMatch.b,\n loaderData: deyhydratedMatch.l,\n status: deyhydratedMatch.s,\n ssr: deyhydratedMatch.ssr,\n updatedAt: deyhydratedMatch.u,\n error: deyhydratedMatch.e,\n }\n}\nexport interface DehydratedMatch {\n i: MakeRouteMatch['id']\n b?: MakeRouteMatch['__beforeLoadContext']\n l?: MakeRouteMatch['loaderData']\n e?: MakeRouteMatch['error']\n u: MakeRouteMatch['updatedAt']\n s: MakeRouteMatch['status']\n ssr?: MakeRouteMatch['ssr']\n}\n\nexport interface DehydratedRouter {\n manifest: Manifest | undefined\n dehydratedData?: any\n lastMatchId?: string\n matches: Array<DehydratedMatch>\n}\n\nexport async function hydrate(router: AnyRouter): Promise<any> {\n invariant(\n window.$_TSR?.router,\n 'Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!',\n )\n\n const { manifest, dehydratedData, lastMatchId } = window.$_TSR.router\n\n router.ssr = {\n manifest,\n }\n\n // Hydrate the router state\n const matches = router.matchRoutes(router.state.location)\n\n // kick off loading the route chunks\n const routeChunkPromise = Promise.all(\n matches.map((match) => {\n const route = router.looseRoutesById[match.routeId]!\n return router.loadRouteChunk(route)\n }),\n )\n\n function setMatchForcePending(match: AnyRouteMatch) {\n // usually the minPendingPromise is created in the Match component if a pending match is rendered\n // however, this might be too late if the match synchronously resolves\n const route = router.looseRoutesById[match.routeId]!\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n if (pendingMinMs) {\n const minPendingPromise = createControlledPromise<void>()\n match.minPendingPromise = minPendingPromise\n match._forcePending = true\n\n setTimeout(() => {\n minPendingPromise.resolve()\n // We've handled the minPendingPromise, so we can delete it\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise: undefined,\n _forcePending: undefined,\n }))\n }, pendingMinMs)\n }\n }\n\n // Right after hydration and before the first render, we need to rehydrate each match\n // First step is to reyhdrate loaderData and __beforeLoadContext\n let firstNonSsrMatchIndex: number | undefined = undefined\n matches.forEach((match) => {\n const dehydratedMatch = window.$_TSR!.router!.matches.find(\n (d) => d.i === match.id,\n )\n if (!dehydratedMatch) {\n Object.assign(match, { dehydrated: false, ssr: false })\n return\n }\n\n Object.assign(match, hydrateMatch(dehydratedMatch))\n\n if (match.ssr === false) {\n match._dehydrated = false\n } else {\n match._dehydrated = true\n }\n\n if (match.ssr === 'data-only' || match.ssr === false) {\n if (firstNonSsrMatchIndex === undefined) {\n firstNonSsrMatchIndex = match.index\n setMatchForcePending(match)\n }\n }\n })\n\n router.__store.setState((s) => {\n return {\n ...s,\n matches,\n }\n })\n\n // Allow the user to handle custom hydration data\n await router.options.hydrate?.(dehydratedData)\n\n // now that all necessary data is hydrated:\n // 1) fully reconstruct the route context\n // 2) execute `head()` and `scripts()` for each match\n await Promise.all(\n router.state.matches.map(async (match) => {\n const route = router.looseRoutesById[match.routeId]!\n\n const parentMatch = router.state.matches[match.index - 1]\n const parentContext = parentMatch?.context ?? router.options.context ?? {}\n\n // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed\n // so run it again and merge route context\n const contextFnContext: RouteContextOptions<any, any, any, any> = {\n deps: match.loaderDeps,\n params: match.params,\n context: parentContext,\n location: router.state.location,\n navigate: (opts: any) =>\n router.navigate({ ...opts, _fromLocation: router.state.location }),\n buildLocation: router.buildLocation,\n cause: match.cause,\n abortController: match.abortController,\n preload: false,\n matches,\n }\n match.__routeContext = route.options.context?.(contextFnContext) ?? {}\n\n match.context = {\n ...parentContext,\n ...match.__routeContext,\n ...match.__beforeLoadContext,\n }\n\n const assetContext = {\n matches: router.state.matches,\n match,\n params: match.params,\n loaderData: match.loaderData,\n }\n const headFnContent = await route.options.head?.(assetContext)\n\n const scripts = await route.options.scripts?.(assetContext)\n\n match.meta = headFnContent?.meta\n match.links = headFnContent?.links\n match.headScripts = headFnContent?.scripts\n match.styles = headFnContent?.styles\n match.scripts = scripts\n }),\n )\n\n const isSpaMode = matches[matches.length - 1]!.id !== lastMatchId\n const hasSsrFalseMatches = matches.some((m) => m.ssr === false)\n // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()\n if (!hasSsrFalseMatches && !isSpaMode) {\n matches.forEach((match) => {\n // remove the _dehydrate flag since we won't run router.load() which would remove it\n match._dehydrated = undefined\n })\n return routeChunkPromise\n }\n\n // schedule router.load() to run after the next tick so we can store the promise in the match before loading starts\n const loadPromise = Promise.resolve()\n .then(() => router.load())\n .catch((err) => {\n console.error('Error during router hydration:', err)\n })\n\n // in SPA mode we need to keep the first match below the root route pending until router.load() is finished\n // this will prevent that other pending components are rendered but hydration is not blocked\n if (isSpaMode) {\n const match = matches[1]\n invariant(\n match,\n 'Expected to find a match below the root match in SPA mode.',\n )\n setMatchForcePending(match)\n\n match._displayPending = true\n match.displayPendingPromise = loadPromise\n\n loadPromise.then(() => {\n batch(() => {\n // ensure router is not in status 'pending' anymore\n // this usually happens in Transitioner but if loading synchronously resolves,\n // Transitioner won't be rendered while loading so it cannot track the change from loading:true to loading:false\n if (router.__store.state.status === 'pending') {\n router.__store.setState((s) => ({\n ...s,\n status: 'idle',\n resolvedLocation: s.location,\n }))\n }\n // hide the pending component once the load is finished\n router.updateMatch(match.id, (prev) => {\n return {\n ...prev,\n _displayPending: undefined,\n displayPendingPromise: undefined,\n }\n })\n })\n })\n }\n return routeChunkPromise\n}\n"],"names":["_b","_a","_c"],"mappings":"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"}
1
+ {"version":3,"file":"ssr-client.js","sources":["../../../src/ssr/ssr-client.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport { batch } from '@tanstack/store'\nimport { createControlledPromise } from '../utils'\nimport type { AnyRouteMatch, MakeRouteMatch } from '../Matches'\nimport type { AnyRouter } from '../router'\nimport type { Manifest } from '../manifest'\nimport type { RouteContextOptions } from '../route'\nimport type { GLOBAL_TSR } from './ssr-server'\n\ndeclare global {\n interface Window {\n [GLOBAL_TSR]?: TsrSsrGlobal\n }\n}\n\nexport interface TsrSsrGlobal {\n router?: DehydratedRouter\n // clean scripts, shortened since this is sent for each streamed script\n c: () => void\n}\n\nfunction hydrateMatch(\n match: AnyRouteMatch,\n deyhydratedMatch: DehydratedMatch,\n): void {\n match.id = deyhydratedMatch.i\n match.__beforeLoadContext = deyhydratedMatch.b\n match.loaderData = deyhydratedMatch.l\n match.status = deyhydratedMatch.s\n match.ssr = deyhydratedMatch.ssr\n match.updatedAt = deyhydratedMatch.u\n match.error = deyhydratedMatch.e\n}\nexport interface DehydratedMatch {\n i: MakeRouteMatch['id']\n b?: MakeRouteMatch['__beforeLoadContext']\n l?: MakeRouteMatch['loaderData']\n e?: MakeRouteMatch['error']\n u: MakeRouteMatch['updatedAt']\n s: MakeRouteMatch['status']\n ssr?: MakeRouteMatch['ssr']\n}\n\nexport interface DehydratedRouter {\n manifest: Manifest | undefined\n dehydratedData?: any\n lastMatchId?: string\n matches: Array<DehydratedMatch>\n}\n\nexport async function hydrate(router: AnyRouter): Promise<any> {\n invariant(\n window.$_TSR?.router,\n 'Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!',\n )\n\n const { manifest, dehydratedData, lastMatchId } = window.$_TSR.router\n\n router.ssr = {\n manifest,\n }\n\n // Hydrate the router state\n const matches = router.matchRoutes(router.state.location)\n\n // kick off loading the route chunks\n const routeChunkPromise = Promise.all(\n matches.map((match) => {\n const route = router.looseRoutesById[match.routeId]!\n return router.loadRouteChunk(route)\n }),\n )\n\n function setMatchForcePending(match: AnyRouteMatch) {\n // usually the minPendingPromise is created in the Match component if a pending match is rendered\n // however, this might be too late if the match synchronously resolves\n const route = router.looseRoutesById[match.routeId]!\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n if (pendingMinMs) {\n const minPendingPromise = createControlledPromise<void>()\n match._nonReactive.minPendingPromise = minPendingPromise\n match._forcePending = true\n\n setTimeout(() => {\n minPendingPromise.resolve()\n // We've handled the minPendingPromise, so we can delete it\n router.updateMatch(match.id, (prev) => {\n prev._nonReactive.minPendingPromise = undefined\n return {\n ...prev,\n _forcePending: undefined,\n }\n })\n }, pendingMinMs)\n }\n }\n\n // Right after hydration and before the first render, we need to rehydrate each match\n // First step is to reyhdrate loaderData and __beforeLoadContext\n let firstNonSsrMatchIndex: number | undefined = undefined\n matches.forEach((match) => {\n const dehydratedMatch = window.$_TSR!.router!.matches.find(\n (d) => d.i === match.id,\n )\n if (!dehydratedMatch) {\n match._nonReactive.dehydrated = false\n match.ssr = false\n return\n }\n\n hydrateMatch(match, dehydratedMatch)\n\n match._nonReactive.dehydrated = match.ssr !== false\n\n if (match.ssr === 'data-only' || match.ssr === false) {\n if (firstNonSsrMatchIndex === undefined) {\n firstNonSsrMatchIndex = match.index\n setMatchForcePending(match)\n }\n }\n })\n\n router.__store.setState((s) => {\n return {\n ...s,\n matches,\n }\n })\n\n // Allow the user to handle custom hydration data\n await router.options.hydrate?.(dehydratedData)\n\n // now that all necessary data is hydrated:\n // 1) fully reconstruct the route context\n // 2) execute `head()` and `scripts()` for each match\n await Promise.all(\n router.state.matches.map(async (match) => {\n const route = router.looseRoutesById[match.routeId]!\n\n const parentMatch = router.state.matches[match.index - 1]\n const parentContext = parentMatch?.context ?? router.options.context ?? {}\n\n // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed\n // so run it again and merge route context\n const contextFnContext: RouteContextOptions<any, any, any, any> = {\n deps: match.loaderDeps,\n params: match.params,\n context: parentContext,\n location: router.state.location,\n navigate: (opts: any) =>\n router.navigate({ ...opts, _fromLocation: router.state.location }),\n buildLocation: router.buildLocation,\n cause: match.cause,\n abortController: match.abortController,\n preload: false,\n matches,\n }\n match.__routeContext = route.options.context?.(contextFnContext) ?? {}\n\n match.context = {\n ...parentContext,\n ...match.__routeContext,\n ...match.__beforeLoadContext,\n }\n\n const assetContext = {\n matches: router.state.matches,\n match,\n params: match.params,\n loaderData: match.loaderData,\n }\n const headFnContent = await route.options.head?.(assetContext)\n\n const scripts = await route.options.scripts?.(assetContext)\n\n match.meta = headFnContent?.meta\n match.links = headFnContent?.links\n match.headScripts = headFnContent?.scripts\n match.styles = headFnContent?.styles\n match.scripts = scripts\n }),\n )\n\n const isSpaMode = matches[matches.length - 1]!.id !== lastMatchId\n const hasSsrFalseMatches = matches.some((m) => m.ssr === false)\n // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()\n if (!hasSsrFalseMatches && !isSpaMode) {\n matches.forEach((match) => {\n // remove the dehydrated flag since we won't run router.load() which would remove it\n match._nonReactive.dehydrated = undefined\n })\n return routeChunkPromise\n }\n\n // schedule router.load() to run after the next tick so we can store the promise in the match before loading starts\n const loadPromise = Promise.resolve()\n .then(() => router.load())\n .catch((err) => {\n console.error('Error during router hydration:', err)\n })\n\n // in SPA mode we need to keep the first match below the root route pending until router.load() is finished\n // this will prevent that other pending components are rendered but hydration is not blocked\n if (isSpaMode) {\n const match = matches[1]\n invariant(\n match,\n 'Expected to find a match below the root match in SPA mode.',\n )\n setMatchForcePending(match)\n\n match._displayPending = true\n match._nonReactive.displayPendingPromise = loadPromise\n\n loadPromise.then(() => {\n batch(() => {\n // ensure router is not in status 'pending' anymore\n // this usually happens in Transitioner but if loading synchronously resolves,\n // Transitioner won't be rendered while loading so it cannot track the change from loading:true to loading:false\n if (router.__store.state.status === 'pending') {\n router.__store.setState((s) => ({\n ...s,\n status: 'idle',\n resolvedLocation: s.location,\n }))\n }\n // hide the pending component once the load is finished\n router.updateMatch(match.id, (prev) => {\n return {\n ...prev,\n _displayPending: undefined,\n displayPendingPromise: undefined,\n }\n })\n })\n })\n }\n return routeChunkPromise\n}\n"],"names":["_b","_a","_c"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
- "version": "1.131.3",
3
+ "version": "1.131.4",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
package/src/Matches.ts CHANGED
@@ -136,11 +136,18 @@ export interface RouteMatch<
136
136
  paramsError: unknown
137
137
  searchError: unknown
138
138
  updatedAt: number
139
- loadPromise?: ControlledPromise<void>
140
- /** @internal */
141
- beforeLoadPromise?: ControlledPromise<void>
142
- /** @internal */
143
- loaderPromise?: ControlledPromise<void>
139
+ _nonReactive: {
140
+ /** @internal */
141
+ beforeLoadPromise?: ControlledPromise<void>
142
+ /** @internal */
143
+ loaderPromise?: ControlledPromise<void>
144
+ /** @internal */
145
+ pendingTimeout?: ReturnType<typeof setTimeout>
146
+ loadPromise?: ControlledPromise<void>
147
+ displayPendingPromise?: Promise<void>
148
+ minPendingPromise?: ControlledPromise<void>
149
+ dehydrated?: boolean
150
+ }
144
151
  loaderData?: TLoaderData
145
152
  /** @internal */
146
153
  __routeContext: Record<string, unknown>
@@ -158,12 +165,9 @@ export interface RouteMatch<
158
165
  headers?: Record<string, string>
159
166
  globalNotFound?: boolean
160
167
  staticData: StaticDataRouteOption
161
- minPendingPromise?: ControlledPromise<void>
162
- pendingTimeout?: ReturnType<typeof setTimeout>
168
+ /** This attribute is not reactive */
163
169
  ssr?: boolean | 'data-only'
164
- _dehydrated?: boolean
165
170
  _forcePending?: boolean
166
- displayPendingPromise?: Promise<void>
167
171
  _displayPending?: boolean
168
172
  }
169
173
 
package/src/router.ts CHANGED
@@ -1285,6 +1285,9 @@ export class RouterCore<
1285
1285
  error: undefined,
1286
1286
  paramsError: parseErrors[index],
1287
1287
  __routeContext: {},
1288
+ _nonReactive: {
1289
+ loadPromise: createControlledPromise(),
1290
+ },
1288
1291
  __beforeLoadContext: undefined,
1289
1292
  context: {},
1290
1293
  abortController: new AbortController(),
@@ -1300,7 +1303,6 @@ export class RouterCore<
1300
1303
  headScripts: undefined,
1301
1304
  meta: undefined,
1302
1305
  staticData: route.options.staticData || {},
1303
- loadPromise: createControlledPromise(),
1304
1306
  fullPath: route.fullPath,
1305
1307
  }
1306
1308
  }
@@ -1388,13 +1390,8 @@ export class RouterCore<
1388
1390
  if (!match) return
1389
1391
 
1390
1392
  match.abortController.abort()
1391
- this.updateMatch(id, (prev) => {
1392
- clearTimeout(prev.pendingTimeout)
1393
- return {
1394
- ...prev,
1395
- pendingTimeout: undefined,
1396
- }
1397
- })
1393
+ match._nonReactive.pendingTimeout = undefined
1394
+ clearTimeout(match._nonReactive.pendingTimeout)
1398
1395
  }
1399
1396
 
1400
1397
  cancelMatches = () => {
@@ -2133,8 +2130,10 @@ export class RouterCore<
2133
2130
  }
2134
2131
  }
2135
2132
 
2136
- match.beforeLoadPromise?.resolve()
2137
- match.loaderPromise?.resolve()
2133
+ match._nonReactive.beforeLoadPromise?.resolve()
2134
+ match._nonReactive.loaderPromise?.resolve()
2135
+ match._nonReactive.beforeLoadPromise = undefined
2136
+ match._nonReactive.loaderPromise = undefined
2138
2137
 
2139
2138
  updateMatch(match.id, (prev) => ({
2140
2139
  ...prev,
@@ -2145,15 +2144,13 @@ export class RouterCore<
2145
2144
  : 'error',
2146
2145
  isFetching: false,
2147
2146
  error: err,
2148
- beforeLoadPromise: undefined,
2149
- loaderPromise: undefined,
2150
2147
  }))
2151
2148
 
2152
2149
  if (!(err as any).routeId) {
2153
2150
  ;(err as any).routeId = match.routeId
2154
2151
  }
2155
2152
 
2156
- match.loadPromise?.resolve()
2153
+ match._nonReactive.loadPromise?.resolve()
2157
2154
 
2158
2155
  if (isRedirect(err)) {
2159
2156
  rendered = true
@@ -2173,7 +2170,7 @@ export class RouterCore<
2173
2170
  const shouldSkipLoader = (matchId: string) => {
2174
2171
  const match = this.getMatch(matchId)!
2175
2172
  // upon hydration, we skip the loader if the match has been dehydrated on the server
2176
- if (!this.isServer && match._dehydrated) {
2173
+ if (!this.isServer && match._nonReactive.dehydrated) {
2177
2174
  return true
2178
2175
  }
2179
2176
 
@@ -2216,8 +2213,9 @@ export class RouterCore<
2216
2213
  }
2217
2214
 
2218
2215
  updateMatch(matchId, (prev) => {
2219
- prev.beforeLoadPromise?.resolve()
2220
- prev.loadPromise?.resolve()
2216
+ prev._nonReactive.beforeLoadPromise?.resolve()
2217
+ prev._nonReactive.beforeLoadPromise = undefined
2218
+ prev._nonReactive.loadPromise?.resolve()
2221
2219
 
2222
2220
  return {
2223
2221
  ...prev,
@@ -2226,7 +2224,6 @@ export class RouterCore<
2226
2224
  isFetching: false,
2227
2225
  updatedAt: Date.now(),
2228
2226
  abortController: new AbortController(),
2229
- beforeLoadPromise: undefined,
2230
2227
  }
2231
2228
  })
2232
2229
  }
@@ -2296,10 +2293,7 @@ export class RouterCore<
2296
2293
  }
2297
2294
  }
2298
2295
  }
2299
- updateMatch(matchId, (prev) => ({
2300
- ...prev,
2301
- ssr,
2302
- }))
2296
+ existingMatch.ssr = ssr
2303
2297
  }
2304
2298
 
2305
2299
  if (shouldSkipLoader(matchId)) {
@@ -2321,9 +2315,10 @@ export class RouterCore<
2321
2315
 
2322
2316
  let executeBeforeLoad = true
2323
2317
  const setupPendingTimeout = () => {
2318
+ const match = this.getMatch(matchId)!
2324
2319
  if (
2325
2320
  shouldPending &&
2326
- this.getMatch(matchId)!.pendingTimeout === undefined
2321
+ match._nonReactive.pendingTimeout === undefined
2327
2322
  ) {
2328
2323
  const pendingTimeout = setTimeout(() => {
2329
2324
  try {
@@ -2332,22 +2327,19 @@ export class RouterCore<
2332
2327
  triggerOnReady()
2333
2328
  } catch {}
2334
2329
  }, pendingMs)
2335
- updateMatch(matchId, (prev) => ({
2336
- ...prev,
2337
- pendingTimeout,
2338
- }))
2330
+ match._nonReactive.pendingTimeout = pendingTimeout
2339
2331
  }
2340
2332
  }
2341
2333
  if (
2342
2334
  // If we are in the middle of a load, either of these will be present
2343
2335
  // (not to be confused with `loadPromise`, which is always defined)
2344
- existingMatch.beforeLoadPromise ||
2345
- existingMatch.loaderPromise
2336
+ existingMatch._nonReactive.beforeLoadPromise ||
2337
+ existingMatch._nonReactive.loaderPromise
2346
2338
  ) {
2347
2339
  setupPendingTimeout()
2348
2340
 
2349
2341
  // Wait for the beforeLoad to resolve before we continue
2350
- await existingMatch.beforeLoadPromise
2342
+ await existingMatch._nonReactive.beforeLoadPromise
2351
2343
  const match = this.getMatch(matchId)!
2352
2344
  if (match.status === 'error') {
2353
2345
  executeBeforeLoad = true
@@ -2361,17 +2353,15 @@ export class RouterCore<
2361
2353
  if (executeBeforeLoad) {
2362
2354
  // If we are not in the middle of a load OR the previous load failed, start it
2363
2355
  try {
2364
- updateMatch(matchId, (prev) => {
2365
- // explicitly capture the previous loadPromise
2366
- const prevLoadPromise = prev.loadPromise
2367
- return {
2368
- ...prev,
2369
- loadPromise: createControlledPromise<void>(() => {
2370
- prevLoadPromise?.resolve()
2371
- }),
2372
- beforeLoadPromise: createControlledPromise<void>(),
2373
- }
2374
- })
2356
+ const match = this.getMatch(matchId)!
2357
+ match._nonReactive.beforeLoadPromise =
2358
+ createControlledPromise<void>()
2359
+ // explicitly capture the previous loadPromise
2360
+ const prevLoadPromise = match._nonReactive.loadPromise
2361
+ match._nonReactive.loadPromise =
2362
+ createControlledPromise<void>(() => {
2363
+ prevLoadPromise?.resolve()
2364
+ })
2375
2365
 
2376
2366
  const { paramsError, searchError } = this.getMatch(matchId)!
2377
2367
 
@@ -2453,11 +2443,11 @@ export class RouterCore<
2453
2443
  }
2454
2444
 
2455
2445
  updateMatch(matchId, (prev) => {
2456
- prev.beforeLoadPromise?.resolve()
2446
+ prev._nonReactive.beforeLoadPromise?.resolve()
2447
+ prev._nonReactive.beforeLoadPromise = undefined
2457
2448
 
2458
2449
  return {
2459
2450
  ...prev,
2460
- beforeLoadPromise: undefined,
2461
2451
  isFetching: false,
2462
2452
  }
2463
2453
  })
@@ -2507,8 +2497,8 @@ export class RouterCore<
2507
2497
 
2508
2498
  const potentialPendingMinPromise = async () => {
2509
2499
  const latestMatch = this.getMatch(matchId)!
2510
- if (latestMatch.minPendingPromise) {
2511
- await latestMatch.minPendingPromise
2500
+ if (latestMatch._nonReactive.minPendingPromise) {
2501
+ await latestMatch._nonReactive.minPendingPromise
2512
2502
  }
2513
2503
  }
2514
2504
 
@@ -2524,7 +2514,7 @@ export class RouterCore<
2524
2514
  }
2525
2515
  }
2526
2516
  // there is a loaderPromise, so we are in the middle of a load
2527
- else if (prevMatch.loaderPromise) {
2517
+ else if (prevMatch._nonReactive.loaderPromise) {
2528
2518
  // do not block if we already have stale data we can show
2529
2519
  // but only if the ongoing load is not a preload since error handling is different for preloads
2530
2520
  // and we don't want to swallow errors
@@ -2535,7 +2525,7 @@ export class RouterCore<
2535
2525
  ) {
2536
2526
  return this.getMatch(matchId)!
2537
2527
  }
2538
- await prevMatch.loaderPromise
2528
+ await prevMatch._nonReactive.loaderPromise
2539
2529
  const match = this.getMatch(matchId)!
2540
2530
  if (match.error) {
2541
2531
  handleRedirectAndNotFound(match, match.error)
@@ -2592,13 +2582,16 @@ export class RouterCore<
2592
2582
  ? shouldReloadOption(getLoaderContext())
2593
2583
  : shouldReloadOption
2594
2584
 
2595
- updateMatch(matchId, (prev) => ({
2596
- ...prev,
2597
- loaderPromise: createControlledPromise<void>(),
2598
- preload:
2599
- !!preload &&
2600
- !this.state.matches.some((d) => d.id === matchId),
2601
- }))
2585
+ updateMatch(matchId, (prev) => {
2586
+ prev._nonReactive.loaderPromise =
2587
+ createControlledPromise<void>()
2588
+ return {
2589
+ ...prev,
2590
+ preload:
2591
+ !!preload &&
2592
+ !this.state.matches.some((d) => d.id === matchId),
2593
+ }
2594
+ })
2602
2595
 
2603
2596
  const runLoader = async () => {
2604
2597
  try {
@@ -2682,11 +2675,13 @@ export class RouterCore<
2682
2675
  } catch (err) {
2683
2676
  const head = await executeHead()
2684
2677
 
2685
- updateMatch(matchId, (prev) => ({
2686
- ...prev,
2687
- loaderPromise: undefined,
2688
- ...head,
2689
- }))
2678
+ updateMatch(matchId, (prev) => {
2679
+ prev._nonReactive.loaderPromise = undefined
2680
+ return {
2681
+ ...prev,
2682
+ ...head,
2683
+ }
2684
+ })
2690
2685
  handleRedirectAndNotFound(this.getMatch(matchId)!, err)
2691
2686
  }
2692
2687
  }
@@ -2703,14 +2698,10 @@ export class RouterCore<
2703
2698
  ;(async () => {
2704
2699
  try {
2705
2700
  await runLoader()
2706
- const { loaderPromise, loadPromise } =
2707
- this.getMatch(matchId)!
2708
- loaderPromise?.resolve()
2709
- loadPromise?.resolve()
2710
- updateMatch(matchId, (prev) => ({
2711
- ...prev,
2712
- loaderPromise: undefined,
2713
- }))
2701
+ const match = this.getMatch(matchId)!
2702
+ match._nonReactive.loaderPromise?.resolve()
2703
+ match._nonReactive.loadPromise?.resolve()
2704
+ match._nonReactive.loaderPromise = undefined
2714
2705
  } catch (err) {
2715
2706
  if (isRedirect(err)) {
2716
2707
  await this.navigate(err.options)
@@ -2734,25 +2725,23 @@ export class RouterCore<
2734
2725
  }
2735
2726
  }
2736
2727
  if (!loaderIsRunningAsync) {
2737
- const { loaderPromise, loadPromise } =
2738
- this.getMatch(matchId)!
2739
- loaderPromise?.resolve()
2740
- loadPromise?.resolve()
2728
+ const match = this.getMatch(matchId)!
2729
+ match._nonReactive.loaderPromise?.resolve()
2730
+ match._nonReactive.loadPromise?.resolve()
2741
2731
  }
2742
2732
 
2743
2733
  updateMatch(matchId, (prev) => {
2744
- clearTimeout(prev.pendingTimeout)
2734
+ clearTimeout(prev._nonReactive.pendingTimeout)
2735
+ prev._nonReactive.pendingTimeout = undefined
2736
+ if (!loaderIsRunningAsync)
2737
+ prev._nonReactive.loaderPromise = undefined
2738
+ prev._nonReactive.dehydrated = undefined
2745
2739
  return {
2746
2740
  ...prev,
2747
2741
  isFetching: loaderIsRunningAsync
2748
2742
  ? prev.isFetching
2749
2743
  : false,
2750
- loaderPromise: loaderIsRunningAsync
2751
- ? prev.loaderPromise
2752
- : undefined,
2753
2744
  invalid: false,
2754
- pendingTimeout: undefined,
2755
- _dehydrated: undefined,
2756
2745
  }
2757
2746
  })
2758
2747
  return this.getMatch(matchId)!
@@ -20,17 +20,16 @@ export interface TsrSsrGlobal {
20
20
  }
21
21
 
22
22
  function hydrateMatch(
23
+ match: AnyRouteMatch,
23
24
  deyhydratedMatch: DehydratedMatch,
24
- ): Partial<MakeRouteMatch> {
25
- return {
26
- id: deyhydratedMatch.i,
27
- __beforeLoadContext: deyhydratedMatch.b,
28
- loaderData: deyhydratedMatch.l,
29
- status: deyhydratedMatch.s,
30
- ssr: deyhydratedMatch.ssr,
31
- updatedAt: deyhydratedMatch.u,
32
- error: deyhydratedMatch.e,
33
- }
25
+ ): void {
26
+ match.id = deyhydratedMatch.i
27
+ match.__beforeLoadContext = deyhydratedMatch.b
28
+ match.loaderData = deyhydratedMatch.l
29
+ match.status = deyhydratedMatch.s
30
+ match.ssr = deyhydratedMatch.ssr
31
+ match.updatedAt = deyhydratedMatch.u
32
+ match.error = deyhydratedMatch.e
34
33
  }
35
34
  export interface DehydratedMatch {
36
35
  i: MakeRouteMatch['id']
@@ -80,17 +79,19 @@ export async function hydrate(router: AnyRouter): Promise<any> {
80
79
  route.options.pendingMinMs ?? router.options.defaultPendingMinMs
81
80
  if (pendingMinMs) {
82
81
  const minPendingPromise = createControlledPromise<void>()
83
- match.minPendingPromise = minPendingPromise
82
+ match._nonReactive.minPendingPromise = minPendingPromise
84
83
  match._forcePending = true
85
84
 
86
85
  setTimeout(() => {
87
86
  minPendingPromise.resolve()
88
87
  // We've handled the minPendingPromise, so we can delete it
89
- router.updateMatch(match.id, (prev) => ({
90
- ...prev,
91
- minPendingPromise: undefined,
92
- _forcePending: undefined,
93
- }))
88
+ router.updateMatch(match.id, (prev) => {
89
+ prev._nonReactive.minPendingPromise = undefined
90
+ return {
91
+ ...prev,
92
+ _forcePending: undefined,
93
+ }
94
+ })
94
95
  }, pendingMinMs)
95
96
  }
96
97
  }
@@ -103,17 +104,14 @@ export async function hydrate(router: AnyRouter): Promise<any> {
103
104
  (d) => d.i === match.id,
104
105
  )
105
106
  if (!dehydratedMatch) {
106
- Object.assign(match, { dehydrated: false, ssr: false })
107
+ match._nonReactive.dehydrated = false
108
+ match.ssr = false
107
109
  return
108
110
  }
109
111
 
110
- Object.assign(match, hydrateMatch(dehydratedMatch))
112
+ hydrateMatch(match, dehydratedMatch)
111
113
 
112
- if (match.ssr === false) {
113
- match._dehydrated = false
114
- } else {
115
- match._dehydrated = true
116
- }
114
+ match._nonReactive.dehydrated = match.ssr !== false
117
115
 
118
116
  if (match.ssr === 'data-only' || match.ssr === false) {
119
117
  if (firstNonSsrMatchIndex === undefined) {
@@ -186,11 +184,11 @@ export async function hydrate(router: AnyRouter): Promise<any> {
186
184
 
187
185
  const isSpaMode = matches[matches.length - 1]!.id !== lastMatchId
188
186
  const hasSsrFalseMatches = matches.some((m) => m.ssr === false)
189
- // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()
187
+ // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()
190
188
  if (!hasSsrFalseMatches && !isSpaMode) {
191
189
  matches.forEach((match) => {
192
- // remove the _dehydrate flag since we won't run router.load() which would remove it
193
- match._dehydrated = undefined
190
+ // remove the dehydrated flag since we won't run router.load() which would remove it
191
+ match._nonReactive.dehydrated = undefined
194
192
  })
195
193
  return routeChunkPromise
196
194
  }
@@ -213,7 +211,7 @@ export async function hydrate(router: AnyRouter): Promise<any> {
213
211
  setMatchForcePending(match)
214
212
 
215
213
  match._displayPending = true
216
- match.displayPendingPromise = loadPromise
214
+ match._nonReactive.displayPendingPromise = loadPromise
217
215
 
218
216
  loadPromise.then(() => {
219
217
  batch(() => {