@tanstack/router-core 1.157.16 → 1.158.0
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/cjs/load-matches.cjs +1 -0
- package/dist/cjs/load-matches.cjs.map +1 -1
- package/dist/cjs/path.cjs +5 -2
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +1 -1
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +7 -6
- package/dist/cjs/router.cjs +31 -25
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +1 -0
- package/dist/cjs/ssr/ssr-client.cjs +2 -1
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/esm/load-matches.js +1 -0
- package/dist/esm/load-matches.js.map +1 -1
- package/dist/esm/path.d.ts +1 -1
- package/dist/esm/path.js +5 -2
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/route.d.ts +7 -6
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +1 -0
- package/dist/esm/router.js +31 -25
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/ssr/ssr-client.js +2 -1
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/package.json +1 -1
- package/src/load-matches.ts +2 -0
- package/src/path.ts +5 -2
- package/src/route.ts +12 -4
- package/src/router.ts +49 -46
- package/src/ssr/ssr-client.ts +18 -16
|
@@ -119,7 +119,8 @@ async function hydrate(router) {
|
|
|
119
119
|
cause: match.cause,
|
|
120
120
|
abortController: match.abortController,
|
|
121
121
|
preload: false,
|
|
122
|
-
matches
|
|
122
|
+
matches,
|
|
123
|
+
routeId: route.id
|
|
123
124
|
};
|
|
124
125
|
match.__routeContext = route.options.context(contextFnContext) ?? void 0;
|
|
125
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-client.js","sources":["../../../src/ssr/ssr-client.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport { batch } from '../utils/batch'\nimport { isNotFound } from '../not-found'\nimport { createControlledPromise } from '../utils'\nimport type { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'\nimport type { DehydratedMatch, TsrSsrGlobal } from './types'\nimport type { AnyRouteMatch } from '../Matches'\nimport type { AnyRouter } from '../router'\nimport type { RouteContextOptions } from '../route'\nimport type { AnySerializationAdapter } from './serializer/transformer'\n\ndeclare global {\n interface Window {\n [GLOBAL_TSR]?: TsrSsrGlobal\n [GLOBAL_SEROVAL]?: any\n }\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}\n\nexport async function hydrate(router: AnyRouter): Promise<any> {\n invariant(\n window.$_TSR,\n 'Expected to find bootstrap data on window.$_TSR, but we did not. Please file an issue!',\n )\n\n const serializationAdapters = router.options.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n\n if (serializationAdapters?.length) {\n const fromSerializableMap = new Map()\n serializationAdapters.forEach((adapter) => {\n fromSerializableMap.set(adapter.key, adapter.fromSerializable)\n })\n window.$_TSR.t = fromSerializableMap\n window.$_TSR.buffer.forEach((script) => script())\n }\n window.$_TSR.initialized = true\n\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 const meta = document.querySelector('meta[property=\"csp-nonce\"]') as\n | HTMLMetaElement\n | undefined\n const nonce = meta?.content\n router.options.ssr = {\n nonce,\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 function setRouteSsr(match: AnyRouteMatch) {\n const route = router.looseRoutesById[match.routeId]\n if (route) {\n route.options.ssr = match.ssr\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 setRouteSsr(match)\n return\n }\n\n hydrateMatch(match, dehydratedMatch)\n setRouteSsr(match)\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 try {\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 if (route.options.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({\n ...opts,\n _fromLocation: router.state.location,\n }),\n buildLocation: router.buildLocation,\n cause: match.cause,\n abortController: match.abortController,\n preload: false,\n matches,\n }\n match.__routeContext =\n route.options.context(contextFnContext) ?? undefined\n }\n\n match.context = {\n ...parentContext,\n ...match.__routeContext,\n ...match.__beforeLoadContext,\n }\n\n const assetContext = {\n ssr: router.options.ssr,\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 } catch (err) {\n if (isNotFound(err)) {\n match.error = { isNotFound: true }\n console.error(\n `NotFound error during hydration for routeId: ${match.routeId}`,\n err,\n )\n } else {\n match.error = err as any\n console.error(\n `Error during hydration for route ${match.routeId}:`,\n err,\n )\n throw err\n }\n }\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":[],"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 '../utils/batch'\nimport { isNotFound } from '../not-found'\nimport { createControlledPromise } from '../utils'\nimport type { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'\nimport type { DehydratedMatch, TsrSsrGlobal } from './types'\nimport type { AnyRouteMatch } from '../Matches'\nimport type { AnyRouter } from '../router'\nimport type { RouteContextOptions } from '../route'\nimport type { AnySerializationAdapter } from './serializer/transformer'\n\ndeclare global {\n interface Window {\n [GLOBAL_TSR]?: TsrSsrGlobal\n [GLOBAL_SEROVAL]?: any\n }\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}\n\nexport async function hydrate(router: AnyRouter): Promise<any> {\n invariant(\n window.$_TSR,\n 'Expected to find bootstrap data on window.$_TSR, but we did not. Please file an issue!',\n )\n\n const serializationAdapters = router.options.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n\n if (serializationAdapters?.length) {\n const fromSerializableMap = new Map()\n serializationAdapters.forEach((adapter) => {\n fromSerializableMap.set(adapter.key, adapter.fromSerializable)\n })\n window.$_TSR.t = fromSerializableMap\n window.$_TSR.buffer.forEach((script) => script())\n }\n window.$_TSR.initialized = true\n\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 const meta = document.querySelector('meta[property=\"csp-nonce\"]') as\n | HTMLMetaElement\n | undefined\n const nonce = meta?.content\n router.options.ssr = {\n nonce,\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 function setRouteSsr(match: AnyRouteMatch) {\n const route = router.looseRoutesById[match.routeId]\n if (route) {\n route.options.ssr = match.ssr\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 setRouteSsr(match)\n return\n }\n\n hydrateMatch(match, dehydratedMatch)\n setRouteSsr(match)\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 try {\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 if (route.options.context) {\n const contextFnContext: RouteContextOptions<any, any, any, any, any> =\n {\n deps: match.loaderDeps,\n params: match.params,\n context: parentContext ?? {},\n location: router.state.location,\n navigate: (opts: any) =>\n router.navigate({\n ...opts,\n _fromLocation: router.state.location,\n }),\n buildLocation: router.buildLocation,\n cause: match.cause,\n abortController: match.abortController,\n preload: false,\n matches,\n routeId: route.id,\n }\n match.__routeContext =\n route.options.context(contextFnContext) ?? undefined\n }\n\n match.context = {\n ...parentContext,\n ...match.__routeContext,\n ...match.__beforeLoadContext,\n }\n\n const assetContext = {\n ssr: router.options.ssr,\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 } catch (err) {\n if (isNotFound(err)) {\n match.error = { isNotFound: true }\n console.error(\n `NotFound error during hydration for routeId: ${match.routeId}`,\n err,\n )\n } else {\n match.error = err as any\n console.error(\n `Error during hydration for route ${match.routeId}:`,\n err,\n )\n throw err\n }\n }\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":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/load-matches.ts
CHANGED
|
@@ -441,6 +441,7 @@ const executeBeforeLoad = (
|
|
|
441
441
|
any,
|
|
442
442
|
any,
|
|
443
443
|
any,
|
|
444
|
+
any,
|
|
444
445
|
any
|
|
445
446
|
> = {
|
|
446
447
|
search,
|
|
@@ -457,6 +458,7 @@ const executeBeforeLoad = (
|
|
|
457
458
|
buildLocation: inner.router.buildLocation,
|
|
458
459
|
cause: preload ? 'preload' : cause,
|
|
459
460
|
matches: inner.matches,
|
|
461
|
+
routeId: route.id,
|
|
460
462
|
...inner.router.options.additionalContext,
|
|
461
463
|
}
|
|
462
464
|
|
package/src/path.ts
CHANGED
|
@@ -271,7 +271,10 @@ export function interpolatePath({
|
|
|
271
271
|
path,
|
|
272
272
|
params,
|
|
273
273
|
decoder,
|
|
274
|
-
server
|
|
274
|
+
// `server` is marked @internal and stripped from .d.ts by `stripInternal`.
|
|
275
|
+
// We avoid destructuring it in the function signature so the emitted
|
|
276
|
+
// declaration doesn't reference a property that no longer exists.
|
|
277
|
+
...rest
|
|
275
278
|
}: InterpolatePathOptions): InterPolatePathResult {
|
|
276
279
|
// Tracking if any params are missing in the `params` object
|
|
277
280
|
// when interpolating the path
|
|
@@ -283,7 +286,7 @@ export function interpolatePath({
|
|
|
283
286
|
if (!path.includes('$'))
|
|
284
287
|
return { interpolatedPath: path, usedParams, isMissingParams }
|
|
285
288
|
|
|
286
|
-
if (isServer ?? server) {
|
|
289
|
+
if (isServer ?? rest.server) {
|
|
287
290
|
// Fast path for common templates like `/posts/$id` or `/files/$`.
|
|
288
291
|
// Braced segments (`{...}`) are more complex (prefix/suffix/optional) and are
|
|
289
292
|
// handled by the general parser below.
|
package/src/route.ts
CHANGED
|
@@ -862,12 +862,14 @@ export type RouteContextFn<
|
|
|
862
862
|
in out TSearchValidator,
|
|
863
863
|
in out TParams,
|
|
864
864
|
in out TRouterContext,
|
|
865
|
+
in out TRouteId,
|
|
865
866
|
> = (
|
|
866
867
|
ctx: RouteContextOptions<
|
|
867
868
|
TParentRoute,
|
|
868
869
|
TSearchValidator,
|
|
869
870
|
TParams,
|
|
870
|
-
TRouterContext
|
|
871
|
+
TRouterContext,
|
|
872
|
+
TRouteId
|
|
871
873
|
>,
|
|
872
874
|
) => any
|
|
873
875
|
|
|
@@ -949,7 +951,8 @@ export interface FilebaseRouteOptionsInterface<
|
|
|
949
951
|
TParentRoute,
|
|
950
952
|
TParams,
|
|
951
953
|
TRouterContext,
|
|
952
|
-
TLoaderDeps
|
|
954
|
+
TLoaderDeps,
|
|
955
|
+
TId
|
|
953
956
|
>,
|
|
954
957
|
) => any
|
|
955
958
|
>
|
|
@@ -977,6 +980,7 @@ export interface FilebaseRouteOptionsInterface<
|
|
|
977
980
|
TParams,
|
|
978
981
|
TRouterContext,
|
|
979
982
|
TRouteContextFn,
|
|
983
|
+
TId,
|
|
980
984
|
TServerMiddlewares,
|
|
981
985
|
THandlers
|
|
982
986
|
>,
|
|
@@ -1068,6 +1072,7 @@ export type BaseRouteOptions<
|
|
|
1068
1072
|
export interface ContextOptions<
|
|
1069
1073
|
in out TParentRoute extends AnyRoute,
|
|
1070
1074
|
in out TParams,
|
|
1075
|
+
in out TRouteId,
|
|
1071
1076
|
> {
|
|
1072
1077
|
abortController: AbortController
|
|
1073
1078
|
preload: boolean
|
|
@@ -1080,6 +1085,7 @@ export interface ContextOptions<
|
|
|
1080
1085
|
buildLocation: BuildLocationFn
|
|
1081
1086
|
cause: 'preload' | 'enter' | 'stay'
|
|
1082
1087
|
matches: Array<MakeRouteMatchUnion>
|
|
1088
|
+
routeId: TRouteId
|
|
1083
1089
|
}
|
|
1084
1090
|
|
|
1085
1091
|
export interface RouteContextOptions<
|
|
@@ -1087,7 +1093,8 @@ export interface RouteContextOptions<
|
|
|
1087
1093
|
in out TParams,
|
|
1088
1094
|
in out TRouterContext,
|
|
1089
1095
|
in out TLoaderDeps,
|
|
1090
|
-
|
|
1096
|
+
in out TRouteId,
|
|
1097
|
+
> extends ContextOptions<TParentRoute, TParams, TRouteId> {
|
|
1091
1098
|
deps: TLoaderDeps
|
|
1092
1099
|
context: Expand<RouteContextParameter<TParentRoute, TRouterContext>>
|
|
1093
1100
|
}
|
|
@@ -1120,11 +1127,12 @@ export interface BeforeLoadContextOptions<
|
|
|
1120
1127
|
in out TParams,
|
|
1121
1128
|
in out TRouterContext,
|
|
1122
1129
|
in out TRouteContextFn,
|
|
1130
|
+
in out TRouteId,
|
|
1123
1131
|
in out TServerMiddlewares,
|
|
1124
1132
|
in out THandlers,
|
|
1125
1133
|
>
|
|
1126
1134
|
extends
|
|
1127
|
-
ContextOptions<TParentRoute, TParams>,
|
|
1135
|
+
ContextOptions<TParentRoute, TParams, TRouteId>,
|
|
1128
1136
|
FullSearchSchemaOption<TParentRoute, TSearchValidator> {
|
|
1129
1137
|
context: Expand<
|
|
1130
1138
|
BeforeLoadContextParameter<TParentRoute, TRouterContext, TRouteContextFn>
|
package/src/router.ts
CHANGED
|
@@ -1359,6 +1359,16 @@ export class RouterCore<
|
|
|
1359
1359
|
return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts)
|
|
1360
1360
|
}
|
|
1361
1361
|
|
|
1362
|
+
private getParentContext(parentMatch?: AnyRouteMatch) {
|
|
1363
|
+
const parentMatchId = parentMatch?.id
|
|
1364
|
+
|
|
1365
|
+
const parentContext = !parentMatchId
|
|
1366
|
+
? ((this.options.context as any) ?? undefined)
|
|
1367
|
+
: (parentMatch.context ?? this.options.context ?? undefined)
|
|
1368
|
+
|
|
1369
|
+
return parentContext
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1362
1372
|
private matchRoutesInternal(
|
|
1363
1373
|
next: ParsedLocation,
|
|
1364
1374
|
opts?: MatchRoutesOpts,
|
|
@@ -1389,19 +1399,10 @@ export class RouterCore<
|
|
|
1389
1399
|
? findGlobalNotFoundRouteId(this.options.notFoundMode, matchedRoutes)
|
|
1390
1400
|
: undefined
|
|
1391
1401
|
|
|
1392
|
-
const matches
|
|
1393
|
-
|
|
1394
|
-
const getParentContext = (parentMatch?: AnyRouteMatch) => {
|
|
1395
|
-
const parentMatchId = parentMatch?.id
|
|
1396
|
-
|
|
1397
|
-
const parentContext = !parentMatchId
|
|
1398
|
-
? ((this.options.context as any) ?? undefined)
|
|
1399
|
-
: (parentMatch.context ?? this.options.context ?? undefined)
|
|
1402
|
+
const matches = new Array<AnyRouteMatch>(matchedRoutes.length)
|
|
1400
1403
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
matchedRoutes.forEach((route, index) => {
|
|
1404
|
+
for (let index = 0; index < matchedRoutes.length; index++) {
|
|
1405
|
+
const route = matchedRoutes[index]!
|
|
1405
1406
|
// Take each matched route and resolve + validate its search params
|
|
1406
1407
|
// This has to happen serially because each route's search params
|
|
1407
1408
|
// can depend on the parent route's search params
|
|
@@ -1411,11 +1412,10 @@ export class RouterCore<
|
|
|
1411
1412
|
|
|
1412
1413
|
const parentMatch = matches[index - 1]
|
|
1413
1414
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
] = (() => {
|
|
1415
|
+
let preMatchSearch: Record<string, any>
|
|
1416
|
+
let strictMatchSearch: Record<string, any>
|
|
1417
|
+
let searchError: any
|
|
1418
|
+
{
|
|
1419
1419
|
// Validate the search params and stabilize them
|
|
1420
1420
|
const parentSearch = parentMatch?.search ?? next.search
|
|
1421
1421
|
const parentStrictSearch = parentMatch?._strictSearch ?? undefined
|
|
@@ -1425,14 +1425,12 @@ export class RouterCore<
|
|
|
1425
1425
|
validateSearch(route.options.validateSearch, { ...parentSearch }) ??
|
|
1426
1426
|
undefined
|
|
1427
1427
|
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
undefined,
|
|
1435
|
-
]
|
|
1428
|
+
preMatchSearch = {
|
|
1429
|
+
...parentSearch,
|
|
1430
|
+
...strictSearch,
|
|
1431
|
+
}
|
|
1432
|
+
strictMatchSearch = { ...parentStrictSearch, ...strictSearch }
|
|
1433
|
+
searchError = undefined
|
|
1436
1434
|
} catch (err: any) {
|
|
1437
1435
|
let searchParamError = err
|
|
1438
1436
|
if (!(err instanceof SearchParamError)) {
|
|
@@ -1445,9 +1443,11 @@ export class RouterCore<
|
|
|
1445
1443
|
throw searchParamError
|
|
1446
1444
|
}
|
|
1447
1445
|
|
|
1448
|
-
|
|
1446
|
+
preMatchSearch = parentSearch
|
|
1447
|
+
strictMatchSearch = {}
|
|
1448
|
+
searchError = searchParamError
|
|
1449
1449
|
}
|
|
1450
|
-
}
|
|
1450
|
+
}
|
|
1451
1451
|
|
|
1452
1452
|
// This is where we need to call route.options.loaderDeps() to get any additional
|
|
1453
1453
|
// deps that the route's loader function might need to run. We need to do this
|
|
@@ -1589,7 +1589,7 @@ export class RouterCore<
|
|
|
1589
1589
|
// update the searchError if there is one
|
|
1590
1590
|
match.searchError = searchError
|
|
1591
1591
|
|
|
1592
|
-
const parentContext = getParentContext(parentMatch)
|
|
1592
|
+
const parentContext = this.getParentContext(parentMatch)
|
|
1593
1593
|
|
|
1594
1594
|
match.context = {
|
|
1595
1595
|
...parentContext,
|
|
@@ -1597,10 +1597,11 @@ export class RouterCore<
|
|
|
1597
1597
|
...match.__beforeLoadContext,
|
|
1598
1598
|
}
|
|
1599
1599
|
|
|
1600
|
-
matches
|
|
1601
|
-
}
|
|
1600
|
+
matches[index] = match
|
|
1601
|
+
}
|
|
1602
1602
|
|
|
1603
|
-
matches.
|
|
1603
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1604
|
+
const match = matches[index]!
|
|
1604
1605
|
const route = this.looseRoutesById[match.routeId]!
|
|
1605
1606
|
const existingMatch = this.getMatch(match.id)
|
|
1606
1607
|
|
|
@@ -1608,24 +1609,26 @@ export class RouterCore<
|
|
|
1608
1609
|
|
|
1609
1610
|
if (!existingMatch) {
|
|
1610
1611
|
const parentMatch = matches[index - 1]
|
|
1611
|
-
const parentContext = getParentContext(parentMatch)
|
|
1612
|
+
const parentContext = this.getParentContext(parentMatch)
|
|
1612
1613
|
|
|
1613
1614
|
// Update the match's context
|
|
1614
1615
|
|
|
1615
1616
|
if (route.options.context) {
|
|
1616
|
-
const contextFnContext: RouteContextOptions<any, any, any, any> =
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1617
|
+
const contextFnContext: RouteContextOptions<any, any, any, any, any> =
|
|
1618
|
+
{
|
|
1619
|
+
deps: match.loaderDeps,
|
|
1620
|
+
params: match.params,
|
|
1621
|
+
context: parentContext ?? {},
|
|
1622
|
+
location: next,
|
|
1623
|
+
navigate: (opts: any) =>
|
|
1624
|
+
this.navigate({ ...opts, _fromLocation: next }),
|
|
1625
|
+
buildLocation: this.buildLocation,
|
|
1626
|
+
cause: match.cause,
|
|
1627
|
+
abortController: match.abortController,
|
|
1628
|
+
preload: !!match.preload,
|
|
1629
|
+
matches,
|
|
1630
|
+
routeId: route.id,
|
|
1631
|
+
}
|
|
1629
1632
|
// Get the route context
|
|
1630
1633
|
match.__routeContext =
|
|
1631
1634
|
route.options.context(contextFnContext) ?? undefined
|
|
@@ -1637,7 +1640,7 @@ export class RouterCore<
|
|
|
1637
1640
|
...match.__beforeLoadContext,
|
|
1638
1641
|
}
|
|
1639
1642
|
}
|
|
1640
|
-
}
|
|
1643
|
+
}
|
|
1641
1644
|
|
|
1642
1645
|
return matches
|
|
1643
1646
|
}
|
package/src/ssr/ssr-client.ts
CHANGED
|
@@ -160,22 +160,24 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
160
160
|
// `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed
|
|
161
161
|
// so run it again and merge route context
|
|
162
162
|
if (route.options.context) {
|
|
163
|
-
const contextFnContext: RouteContextOptions<any, any, any, any> =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
163
|
+
const contextFnContext: RouteContextOptions<any, any, any, any, any> =
|
|
164
|
+
{
|
|
165
|
+
deps: match.loaderDeps,
|
|
166
|
+
params: match.params,
|
|
167
|
+
context: parentContext ?? {},
|
|
168
|
+
location: router.state.location,
|
|
169
|
+
navigate: (opts: any) =>
|
|
170
|
+
router.navigate({
|
|
171
|
+
...opts,
|
|
172
|
+
_fromLocation: router.state.location,
|
|
173
|
+
}),
|
|
174
|
+
buildLocation: router.buildLocation,
|
|
175
|
+
cause: match.cause,
|
|
176
|
+
abortController: match.abortController,
|
|
177
|
+
preload: false,
|
|
178
|
+
matches,
|
|
179
|
+
routeId: route.id,
|
|
180
|
+
}
|
|
179
181
|
match.__routeContext =
|
|
180
182
|
route.options.context(contextFnContext) ?? undefined
|
|
181
183
|
}
|