@tanstack/router-core 1.131.7 → 1.132.0-alpha.1
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/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +9 -7
- package/dist/cjs/defer.cjs +1 -1
- package/dist/cjs/defer.cjs.map +1 -1
- package/dist/cjs/index.cjs +0 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/lru-cache.cjs.map +1 -1
- package/dist/cjs/not-found.cjs +1 -1
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/path.cjs +10 -12
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/qss.cjs.map +1 -1
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/route.cjs +6 -7
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/router.cjs +168 -196
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +1 -2
- package/dist/cjs/scroll-restoration.cjs +2 -3
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +9 -0
- package/dist/cjs/searchMiddleware.cjs.map +1 -1
- package/dist/cjs/searchParams.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.cjs +2 -3
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/handlerCallback.cjs.map +1 -1
- package/dist/cjs/ssr/headers.cjs.map +1 -1
- package/dist/cjs/ssr/json.cjs +1 -1
- package/dist/cjs/ssr/json.cjs.map +1 -1
- package/dist/cjs/ssr/seroval-plugins.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-client.cjs +47 -48
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.cjs +2 -3
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +3 -4
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
- package/dist/cjs/typePrimitives.d.cts +6 -6
- package/dist/cjs/utils.cjs +4 -27
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +0 -6
- package/dist/esm/Matches.d.ts +9 -7
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/defer.js +1 -1
- package/dist/esm/defer.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -3
- package/dist/esm/lru-cache.js.map +1 -1
- package/dist/esm/not-found.js +1 -1
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/path.js +10 -12
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/qss.js.map +1 -1
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/route.js +6 -7
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +1 -2
- package/dist/esm/router.js +168 -196
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +9 -0
- package/dist/esm/scroll-restoration.js +2 -3
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/searchMiddleware.js.map +1 -1
- package/dist/esm/searchParams.js.map +1 -1
- package/dist/esm/ssr/createRequestHandler.js +2 -3
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/handlerCallback.js.map +1 -1
- package/dist/esm/ssr/headers.js.map +1 -1
- package/dist/esm/ssr/json.js +1 -1
- package/dist/esm/ssr/json.js.map +1 -1
- package/dist/esm/ssr/seroval-plugins.js.map +1 -1
- package/dist/esm/ssr/ssr-client.js +47 -48
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.js +2 -3
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/transformStreamWithRouter.js +3 -4
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
- package/dist/esm/typePrimitives.d.ts +6 -6
- package/dist/esm/utils.d.ts +0 -6
- package/dist/esm/utils.js +5 -28
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/Matches.ts +8 -16
- package/src/index.ts +0 -2
- package/src/router.ts +112 -110
- package/src/ssr/ssr-client.ts +41 -42
- package/src/typePrimitives.ts +6 -6
- package/src/utils.ts +0 -41
package/src/router.ts
CHANGED
|
@@ -614,8 +614,8 @@ export type InvalidateFn<TRouter extends AnyRouter> = (opts?: {
|
|
|
614
614
|
}) => Promise<void>
|
|
615
615
|
|
|
616
616
|
export type ParseLocationFn<TRouteTree extends AnyRoute> = (
|
|
617
|
-
locationToParse: HistoryLocation,
|
|
618
617
|
previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>,
|
|
618
|
+
locationToParse?: HistoryLocation,
|
|
619
619
|
) => ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
620
620
|
|
|
621
621
|
export type GetMatchRoutesFn = (
|
|
@@ -901,7 +901,7 @@ export class RouterCore<
|
|
|
901
901
|
initialEntries: [this.basepath || '/'],
|
|
902
902
|
})
|
|
903
903
|
: createBrowserHistory()) as TRouterHistory)
|
|
904
|
-
this.
|
|
904
|
+
this.latestLocation = this.parseLocation()
|
|
905
905
|
}
|
|
906
906
|
|
|
907
907
|
if (this.options.routeTree !== this.routeTree) {
|
|
@@ -939,13 +939,6 @@ export class RouterCore<
|
|
|
939
939
|
return this.__store.state
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
-
updateLatestLocation = () => {
|
|
943
|
-
this.latestLocation = this.parseLocation(
|
|
944
|
-
this.history.location,
|
|
945
|
-
this.latestLocation,
|
|
946
|
-
)
|
|
947
|
-
}
|
|
948
|
-
|
|
949
942
|
buildRouteTree = () => {
|
|
950
943
|
const { routesById, routesByPath, flatRoutes } = processRouteTree({
|
|
951
944
|
routeTree: this.routeTree,
|
|
@@ -992,8 +985,8 @@ export class RouterCore<
|
|
|
992
985
|
}
|
|
993
986
|
|
|
994
987
|
parseLocation: ParseLocationFn<TRouteTree> = (
|
|
995
|
-
locationToParse,
|
|
996
988
|
previousLocation,
|
|
989
|
+
locationToParse,
|
|
997
990
|
) => {
|
|
998
991
|
const parse = ({
|
|
999
992
|
pathname,
|
|
@@ -1014,7 +1007,7 @@ export class RouterCore<
|
|
|
1014
1007
|
}
|
|
1015
1008
|
}
|
|
1016
1009
|
|
|
1017
|
-
const location = parse(locationToParse)
|
|
1010
|
+
const location = parse(locationToParse ?? this.history.location)
|
|
1018
1011
|
|
|
1019
1012
|
const { __tempLocation, __tempKey } = location.state
|
|
1020
1013
|
|
|
@@ -1146,8 +1139,8 @@ export class RouterCore<
|
|
|
1146
1139
|
const parentMatchId = parentMatch?.id
|
|
1147
1140
|
|
|
1148
1141
|
const parentContext = !parentMatchId
|
|
1149
|
-
? ((this.options.context as any) ??
|
|
1150
|
-
: (parentMatch.context ?? this.options.context ??
|
|
1142
|
+
? ((this.options.context as any) ?? {})
|
|
1143
|
+
: (parentMatch.context ?? this.options.context ?? {})
|
|
1151
1144
|
|
|
1152
1145
|
return parentContext
|
|
1153
1146
|
}
|
|
@@ -1169,12 +1162,12 @@ export class RouterCore<
|
|
|
1169
1162
|
] = (() => {
|
|
1170
1163
|
// Validate the search params and stabilize them
|
|
1171
1164
|
const parentSearch = parentMatch?.search ?? next.search
|
|
1172
|
-
const parentStrictSearch = parentMatch?._strictSearch ??
|
|
1165
|
+
const parentStrictSearch = parentMatch?._strictSearch ?? {}
|
|
1173
1166
|
|
|
1174
1167
|
try {
|
|
1175
1168
|
const strictSearch =
|
|
1176
1169
|
validateSearch(route.options.validateSearch, { ...parentSearch }) ??
|
|
1177
|
-
|
|
1170
|
+
{}
|
|
1178
1171
|
|
|
1179
1172
|
return [
|
|
1180
1173
|
{
|
|
@@ -1284,10 +1277,7 @@ export class RouterCore<
|
|
|
1284
1277
|
isFetching: false,
|
|
1285
1278
|
error: undefined,
|
|
1286
1279
|
paramsError: parseErrors[index],
|
|
1287
|
-
__routeContext:
|
|
1288
|
-
_nonReactive: {
|
|
1289
|
-
loadPromise: createControlledPromise(),
|
|
1290
|
-
},
|
|
1280
|
+
__routeContext: {},
|
|
1291
1281
|
__beforeLoadContext: undefined,
|
|
1292
1282
|
context: {},
|
|
1293
1283
|
abortController: new AbortController(),
|
|
@@ -1303,6 +1293,7 @@ export class RouterCore<
|
|
|
1303
1293
|
headScripts: undefined,
|
|
1304
1294
|
meta: undefined,
|
|
1305
1295
|
staticData: route.options.staticData || {},
|
|
1296
|
+
loadPromise: createControlledPromise(),
|
|
1306
1297
|
fullPath: route.fullPath,
|
|
1307
1298
|
}
|
|
1308
1299
|
}
|
|
@@ -1337,26 +1328,23 @@ export class RouterCore<
|
|
|
1337
1328
|
const parentContext = getParentContext(parentMatch)
|
|
1338
1329
|
|
|
1339
1330
|
// Update the match's context
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
preload: !!match.preload,
|
|
1353
|
-
matches,
|
|
1354
|
-
}
|
|
1355
|
-
// Get the route context
|
|
1356
|
-
match.__routeContext =
|
|
1357
|
-
route.options.context(contextFnContext) ?? undefined
|
|
1331
|
+
const contextFnContext: RouteContextOptions<any, any, any, any> = {
|
|
1332
|
+
deps: match.loaderDeps,
|
|
1333
|
+
params: match.params,
|
|
1334
|
+
context: parentContext,
|
|
1335
|
+
location: next,
|
|
1336
|
+
navigate: (opts: any) =>
|
|
1337
|
+
this.navigate({ ...opts, _fromLocation: next }),
|
|
1338
|
+
buildLocation: this.buildLocation,
|
|
1339
|
+
cause: match.cause,
|
|
1340
|
+
abortController: match.abortController,
|
|
1341
|
+
preload: !!match.preload,
|
|
1342
|
+
matches,
|
|
1358
1343
|
}
|
|
1359
1344
|
|
|
1345
|
+
// Get the route context
|
|
1346
|
+
match.__routeContext = route.options.context?.(contextFnContext) ?? {}
|
|
1347
|
+
|
|
1360
1348
|
match.context = {
|
|
1361
1349
|
...parentContext,
|
|
1362
1350
|
...match.__routeContext,
|
|
@@ -1393,8 +1381,13 @@ export class RouterCore<
|
|
|
1393
1381
|
if (!match) return
|
|
1394
1382
|
|
|
1395
1383
|
match.abortController.abort()
|
|
1396
|
-
|
|
1397
|
-
|
|
1384
|
+
this.updateMatch(id, (prev) => {
|
|
1385
|
+
clearTimeout(prev.pendingTimeout)
|
|
1386
|
+
return {
|
|
1387
|
+
...prev,
|
|
1388
|
+
pendingTimeout: undefined,
|
|
1389
|
+
}
|
|
1390
|
+
})
|
|
1398
1391
|
}
|
|
1399
1392
|
|
|
1400
1393
|
cancelMatches = () => {
|
|
@@ -1420,7 +1413,7 @@ export class RouterCore<
|
|
|
1420
1413
|
|
|
1421
1414
|
// First let's find the starting pathname
|
|
1422
1415
|
// By default, start with the current location
|
|
1423
|
-
let fromPath =
|
|
1416
|
+
let fromPath = lastMatch.fullPath
|
|
1424
1417
|
const toPath = dest.to
|
|
1425
1418
|
? this.resolvePathWithBase(fromPath, `${dest.to}`)
|
|
1426
1419
|
: this.resolvePathWithBase(fromPath, '.')
|
|
@@ -1461,8 +1454,6 @@ export class RouterCore<
|
|
|
1461
1454
|
}
|
|
1462
1455
|
}
|
|
1463
1456
|
|
|
1464
|
-
fromPath = this.resolvePathWithBase(fromPath, '.')
|
|
1465
|
-
|
|
1466
1457
|
// From search should always use the current location
|
|
1467
1458
|
const fromSearch = lastMatch.search
|
|
1468
1459
|
// Same with params. It can't hurt to provide as many as possible
|
|
@@ -1491,9 +1482,13 @@ export class RouterCore<
|
|
|
1491
1482
|
parseCache: this.parsePathnameCache,
|
|
1492
1483
|
}).interpolatedPath
|
|
1493
1484
|
|
|
1494
|
-
const destRoutes = this.matchRoutes(
|
|
1495
|
-
|
|
1496
|
-
|
|
1485
|
+
const destRoutes = this.matchRoutes(
|
|
1486
|
+
interpolatedNextTo,
|
|
1487
|
+
{},
|
|
1488
|
+
{
|
|
1489
|
+
_buildLocation: true,
|
|
1490
|
+
},
|
|
1491
|
+
).map((d) => this.looseRoutesById[d.routeId]!)
|
|
1497
1492
|
|
|
1498
1493
|
// If there are any params, we need to stringify them
|
|
1499
1494
|
if (Object.keys(nextParams).length > 0) {
|
|
@@ -1810,7 +1805,7 @@ export class RouterCore<
|
|
|
1810
1805
|
beforeLoad = () => {
|
|
1811
1806
|
// Cancel any pending matches
|
|
1812
1807
|
this.cancelMatches()
|
|
1813
|
-
this.
|
|
1808
|
+
this.latestLocation = this.parseLocation(this.latestLocation)
|
|
1814
1809
|
|
|
1815
1810
|
if (this.isServer) {
|
|
1816
1811
|
// for SPAs on the initial load, this is handled by the Transitioner
|
|
@@ -2131,10 +2126,8 @@ export class RouterCore<
|
|
|
2131
2126
|
}
|
|
2132
2127
|
}
|
|
2133
2128
|
|
|
2134
|
-
match.
|
|
2135
|
-
match.
|
|
2136
|
-
match._nonReactive.beforeLoadPromise = undefined
|
|
2137
|
-
match._nonReactive.loaderPromise = undefined
|
|
2129
|
+
match.beforeLoadPromise?.resolve()
|
|
2130
|
+
match.loaderPromise?.resolve()
|
|
2138
2131
|
|
|
2139
2132
|
updateMatch(match.id, (prev) => ({
|
|
2140
2133
|
...prev,
|
|
@@ -2145,13 +2138,15 @@ export class RouterCore<
|
|
|
2145
2138
|
: 'error',
|
|
2146
2139
|
isFetching: false,
|
|
2147
2140
|
error: err,
|
|
2141
|
+
beforeLoadPromise: undefined,
|
|
2142
|
+
loaderPromise: undefined,
|
|
2148
2143
|
}))
|
|
2149
2144
|
|
|
2150
2145
|
if (!(err as any).routeId) {
|
|
2151
2146
|
;(err as any).routeId = match.routeId
|
|
2152
2147
|
}
|
|
2153
2148
|
|
|
2154
|
-
match.
|
|
2149
|
+
match.loadPromise?.resolve()
|
|
2155
2150
|
|
|
2156
2151
|
if (isRedirect(err)) {
|
|
2157
2152
|
rendered = true
|
|
@@ -2171,7 +2166,7 @@ export class RouterCore<
|
|
|
2171
2166
|
const shouldSkipLoader = (matchId: string) => {
|
|
2172
2167
|
const match = this.getMatch(matchId)!
|
|
2173
2168
|
// upon hydration, we skip the loader if the match has been dehydrated on the server
|
|
2174
|
-
if (!this.isServer && match.
|
|
2169
|
+
if (!this.isServer && match._dehydrated) {
|
|
2175
2170
|
return true
|
|
2176
2171
|
}
|
|
2177
2172
|
|
|
@@ -2214,9 +2209,8 @@ export class RouterCore<
|
|
|
2214
2209
|
}
|
|
2215
2210
|
|
|
2216
2211
|
updateMatch(matchId, (prev) => {
|
|
2217
|
-
prev.
|
|
2218
|
-
prev.
|
|
2219
|
-
prev._nonReactive.loadPromise?.resolve()
|
|
2212
|
+
prev.beforeLoadPromise?.resolve()
|
|
2213
|
+
prev.loadPromise?.resolve()
|
|
2220
2214
|
|
|
2221
2215
|
return {
|
|
2222
2216
|
...prev,
|
|
@@ -2225,6 +2219,7 @@ export class RouterCore<
|
|
|
2225
2219
|
isFetching: false,
|
|
2226
2220
|
updatedAt: Date.now(),
|
|
2227
2221
|
abortController: new AbortController(),
|
|
2222
|
+
beforeLoadPromise: undefined,
|
|
2228
2223
|
}
|
|
2229
2224
|
})
|
|
2230
2225
|
}
|
|
@@ -2294,7 +2289,10 @@ export class RouterCore<
|
|
|
2294
2289
|
}
|
|
2295
2290
|
}
|
|
2296
2291
|
}
|
|
2297
|
-
|
|
2292
|
+
updateMatch(matchId, (prev) => ({
|
|
2293
|
+
...prev,
|
|
2294
|
+
ssr,
|
|
2295
|
+
}))
|
|
2298
2296
|
}
|
|
2299
2297
|
|
|
2300
2298
|
if (shouldSkipLoader(matchId)) {
|
|
@@ -2316,10 +2314,9 @@ export class RouterCore<
|
|
|
2316
2314
|
|
|
2317
2315
|
let executeBeforeLoad = true
|
|
2318
2316
|
const setupPendingTimeout = () => {
|
|
2319
|
-
const match = this.getMatch(matchId)!
|
|
2320
2317
|
if (
|
|
2321
2318
|
shouldPending &&
|
|
2322
|
-
|
|
2319
|
+
this.getMatch(matchId)!.pendingTimeout === undefined
|
|
2323
2320
|
) {
|
|
2324
2321
|
const pendingTimeout = setTimeout(() => {
|
|
2325
2322
|
try {
|
|
@@ -2328,19 +2325,22 @@ export class RouterCore<
|
|
|
2328
2325
|
triggerOnReady()
|
|
2329
2326
|
} catch {}
|
|
2330
2327
|
}, pendingMs)
|
|
2331
|
-
|
|
2328
|
+
updateMatch(matchId, (prev) => ({
|
|
2329
|
+
...prev,
|
|
2330
|
+
pendingTimeout,
|
|
2331
|
+
}))
|
|
2332
2332
|
}
|
|
2333
2333
|
}
|
|
2334
2334
|
if (
|
|
2335
2335
|
// If we are in the middle of a load, either of these will be present
|
|
2336
2336
|
// (not to be confused with `loadPromise`, which is always defined)
|
|
2337
|
-
existingMatch.
|
|
2338
|
-
existingMatch.
|
|
2337
|
+
existingMatch.beforeLoadPromise ||
|
|
2338
|
+
existingMatch.loaderPromise
|
|
2339
2339
|
) {
|
|
2340
2340
|
setupPendingTimeout()
|
|
2341
2341
|
|
|
2342
2342
|
// Wait for the beforeLoad to resolve before we continue
|
|
2343
|
-
await existingMatch.
|
|
2343
|
+
await existingMatch.beforeLoadPromise
|
|
2344
2344
|
const match = this.getMatch(matchId)!
|
|
2345
2345
|
if (match.status === 'error') {
|
|
2346
2346
|
executeBeforeLoad = true
|
|
@@ -2354,15 +2354,17 @@ export class RouterCore<
|
|
|
2354
2354
|
if (executeBeforeLoad) {
|
|
2355
2355
|
// If we are not in the middle of a load OR the previous load failed, start it
|
|
2356
2356
|
try {
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2357
|
+
updateMatch(matchId, (prev) => {
|
|
2358
|
+
// explicitly capture the previous loadPromise
|
|
2359
|
+
const prevLoadPromise = prev.loadPromise
|
|
2360
|
+
return {
|
|
2361
|
+
...prev,
|
|
2362
|
+
loadPromise: createControlledPromise<void>(() => {
|
|
2363
|
+
prevLoadPromise?.resolve()
|
|
2364
|
+
}),
|
|
2365
|
+
beforeLoadPromise: createControlledPromise<void>(),
|
|
2366
|
+
}
|
|
2367
|
+
})
|
|
2366
2368
|
|
|
2367
2369
|
const { paramsError, searchError } = this.getMatch(matchId)!
|
|
2368
2370
|
|
|
@@ -2379,7 +2381,7 @@ export class RouterCore<
|
|
|
2379
2381
|
const abortController = new AbortController()
|
|
2380
2382
|
|
|
2381
2383
|
const parentMatchContext =
|
|
2382
|
-
parentMatch?.context ?? this.options.context ??
|
|
2384
|
+
parentMatch?.context ?? this.options.context ?? {}
|
|
2383
2385
|
|
|
2384
2386
|
updateMatch(matchId, (prev) => ({
|
|
2385
2387
|
...prev,
|
|
@@ -2444,11 +2446,11 @@ export class RouterCore<
|
|
|
2444
2446
|
}
|
|
2445
2447
|
|
|
2446
2448
|
updateMatch(matchId, (prev) => {
|
|
2447
|
-
prev.
|
|
2448
|
-
prev._nonReactive.beforeLoadPromise = undefined
|
|
2449
|
+
prev.beforeLoadPromise?.resolve()
|
|
2449
2450
|
|
|
2450
2451
|
return {
|
|
2451
2452
|
...prev,
|
|
2453
|
+
beforeLoadPromise: undefined,
|
|
2452
2454
|
isFetching: false,
|
|
2453
2455
|
}
|
|
2454
2456
|
})
|
|
@@ -2498,8 +2500,8 @@ export class RouterCore<
|
|
|
2498
2500
|
|
|
2499
2501
|
const potentialPendingMinPromise = async () => {
|
|
2500
2502
|
const latestMatch = this.getMatch(matchId)!
|
|
2501
|
-
if (latestMatch.
|
|
2502
|
-
await latestMatch.
|
|
2503
|
+
if (latestMatch.minPendingPromise) {
|
|
2504
|
+
await latestMatch.minPendingPromise
|
|
2503
2505
|
}
|
|
2504
2506
|
}
|
|
2505
2507
|
|
|
@@ -2515,7 +2517,7 @@ export class RouterCore<
|
|
|
2515
2517
|
}
|
|
2516
2518
|
}
|
|
2517
2519
|
// there is a loaderPromise, so we are in the middle of a load
|
|
2518
|
-
else if (prevMatch.
|
|
2520
|
+
else if (prevMatch.loaderPromise) {
|
|
2519
2521
|
// do not block if we already have stale data we can show
|
|
2520
2522
|
// but only if the ongoing load is not a preload since error handling is different for preloads
|
|
2521
2523
|
// and we don't want to swallow errors
|
|
@@ -2526,7 +2528,7 @@ export class RouterCore<
|
|
|
2526
2528
|
) {
|
|
2527
2529
|
return this.getMatch(matchId)!
|
|
2528
2530
|
}
|
|
2529
|
-
await prevMatch.
|
|
2531
|
+
await prevMatch.loaderPromise
|
|
2530
2532
|
const match = this.getMatch(matchId)!
|
|
2531
2533
|
if (match.error) {
|
|
2532
2534
|
handleRedirectAndNotFound(match, match.error)
|
|
@@ -2583,16 +2585,13 @@ export class RouterCore<
|
|
|
2583
2585
|
? shouldReloadOption(getLoaderContext())
|
|
2584
2586
|
: shouldReloadOption
|
|
2585
2587
|
|
|
2586
|
-
updateMatch(matchId, (prev) => {
|
|
2587
|
-
prev
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
!this.state.matches.some((d) => d.id === matchId),
|
|
2594
|
-
}
|
|
2595
|
-
})
|
|
2588
|
+
updateMatch(matchId, (prev) => ({
|
|
2589
|
+
...prev,
|
|
2590
|
+
loaderPromise: createControlledPromise<void>(),
|
|
2591
|
+
preload:
|
|
2592
|
+
!!preload &&
|
|
2593
|
+
!this.state.matches.some((d) => d.id === matchId),
|
|
2594
|
+
}))
|
|
2596
2595
|
|
|
2597
2596
|
const runLoader = async () => {
|
|
2598
2597
|
try {
|
|
@@ -2676,13 +2675,11 @@ export class RouterCore<
|
|
|
2676
2675
|
} catch (err) {
|
|
2677
2676
|
const head = await executeHead()
|
|
2678
2677
|
|
|
2679
|
-
updateMatch(matchId, (prev) => {
|
|
2680
|
-
prev
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
}
|
|
2685
|
-
})
|
|
2678
|
+
updateMatch(matchId, (prev) => ({
|
|
2679
|
+
...prev,
|
|
2680
|
+
loaderPromise: undefined,
|
|
2681
|
+
...head,
|
|
2682
|
+
}))
|
|
2686
2683
|
handleRedirectAndNotFound(this.getMatch(matchId)!, err)
|
|
2687
2684
|
}
|
|
2688
2685
|
}
|
|
@@ -2699,10 +2696,14 @@ export class RouterCore<
|
|
|
2699
2696
|
;(async () => {
|
|
2700
2697
|
try {
|
|
2701
2698
|
await runLoader()
|
|
2702
|
-
const
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2699
|
+
const { loaderPromise, loadPromise } =
|
|
2700
|
+
this.getMatch(matchId)!
|
|
2701
|
+
loaderPromise?.resolve()
|
|
2702
|
+
loadPromise?.resolve()
|
|
2703
|
+
updateMatch(matchId, (prev) => ({
|
|
2704
|
+
...prev,
|
|
2705
|
+
loaderPromise: undefined,
|
|
2706
|
+
}))
|
|
2706
2707
|
} catch (err) {
|
|
2707
2708
|
if (isRedirect(err)) {
|
|
2708
2709
|
await this.navigate(err.options)
|
|
@@ -2726,23 +2727,25 @@ export class RouterCore<
|
|
|
2726
2727
|
}
|
|
2727
2728
|
}
|
|
2728
2729
|
if (!loaderIsRunningAsync) {
|
|
2729
|
-
const
|
|
2730
|
-
|
|
2731
|
-
|
|
2730
|
+
const { loaderPromise, loadPromise } =
|
|
2731
|
+
this.getMatch(matchId)!
|
|
2732
|
+
loaderPromise?.resolve()
|
|
2733
|
+
loadPromise?.resolve()
|
|
2732
2734
|
}
|
|
2733
2735
|
|
|
2734
2736
|
updateMatch(matchId, (prev) => {
|
|
2735
|
-
clearTimeout(prev.
|
|
2736
|
-
prev._nonReactive.pendingTimeout = undefined
|
|
2737
|
-
if (!loaderIsRunningAsync)
|
|
2738
|
-
prev._nonReactive.loaderPromise = undefined
|
|
2739
|
-
prev._nonReactive.dehydrated = undefined
|
|
2737
|
+
clearTimeout(prev.pendingTimeout)
|
|
2740
2738
|
return {
|
|
2741
2739
|
...prev,
|
|
2742
2740
|
isFetching: loaderIsRunningAsync
|
|
2743
2741
|
? prev.isFetching
|
|
2744
2742
|
: false,
|
|
2743
|
+
loaderPromise: loaderIsRunningAsync
|
|
2744
|
+
? prev.loaderPromise
|
|
2745
|
+
: undefined,
|
|
2745
2746
|
invalid: false,
|
|
2747
|
+
pendingTimeout: undefined,
|
|
2748
|
+
_dehydrated: undefined,
|
|
2746
2749
|
}
|
|
2747
2750
|
})
|
|
2748
2751
|
return this.getMatch(matchId)!
|
|
@@ -2788,7 +2791,7 @@ export class RouterCore<
|
|
|
2788
2791
|
invalid: true,
|
|
2789
2792
|
...(opts?.forcePending || d.status === 'error'
|
|
2790
2793
|
? ({ status: 'pending', error: undefined } as const)
|
|
2791
|
-
:
|
|
2794
|
+
: {}),
|
|
2792
2795
|
}
|
|
2793
2796
|
}
|
|
2794
2797
|
return d
|
|
@@ -3559,8 +3562,7 @@ function applySearchMiddleware({
|
|
|
3559
3562
|
try {
|
|
3560
3563
|
const validatedSearch = {
|
|
3561
3564
|
...result,
|
|
3562
|
-
...(validateSearch(route.options.validateSearch, result) ??
|
|
3563
|
-
undefined),
|
|
3565
|
+
...(validateSearch(route.options.validateSearch, result) ?? {}),
|
|
3564
3566
|
}
|
|
3565
3567
|
return validatedSearch
|
|
3566
3568
|
} catch {
|
package/src/ssr/ssr-client.ts
CHANGED
|
@@ -20,16 +20,17 @@ export interface TsrSsrGlobal {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function hydrateMatch(
|
|
23
|
-
match: AnyRouteMatch,
|
|
24
23
|
deyhydratedMatch: DehydratedMatch,
|
|
25
|
-
):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
33
34
|
}
|
|
34
35
|
export interface DehydratedMatch {
|
|
35
36
|
i: MakeRouteMatch['id']
|
|
@@ -79,19 +80,17 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
79
80
|
route.options.pendingMinMs ?? router.options.defaultPendingMinMs
|
|
80
81
|
if (pendingMinMs) {
|
|
81
82
|
const minPendingPromise = createControlledPromise<void>()
|
|
82
|
-
match.
|
|
83
|
+
match.minPendingPromise = minPendingPromise
|
|
83
84
|
match._forcePending = true
|
|
84
85
|
|
|
85
86
|
setTimeout(() => {
|
|
86
87
|
minPendingPromise.resolve()
|
|
87
88
|
// We've handled the minPendingPromise, so we can delete it
|
|
88
|
-
router.updateMatch(match.id, (prev) => {
|
|
89
|
-
prev
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
})
|
|
89
|
+
router.updateMatch(match.id, (prev) => ({
|
|
90
|
+
...prev,
|
|
91
|
+
minPendingPromise: undefined,
|
|
92
|
+
_forcePending: undefined,
|
|
93
|
+
}))
|
|
95
94
|
}, pendingMinMs)
|
|
96
95
|
}
|
|
97
96
|
}
|
|
@@ -104,14 +103,17 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
104
103
|
(d) => d.i === match.id,
|
|
105
104
|
)
|
|
106
105
|
if (!dehydratedMatch) {
|
|
107
|
-
match
|
|
108
|
-
match.ssr = false
|
|
106
|
+
Object.assign(match, { dehydrated: false, ssr: false })
|
|
109
107
|
return
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
|
|
110
|
+
Object.assign(match, hydrateMatch(dehydratedMatch))
|
|
113
111
|
|
|
114
|
-
|
|
112
|
+
if (match.ssr === false) {
|
|
113
|
+
match._dehydrated = false
|
|
114
|
+
} else {
|
|
115
|
+
match._dehydrated = true
|
|
116
|
+
}
|
|
115
117
|
|
|
116
118
|
if (match.ssr === 'data-only' || match.ssr === false) {
|
|
117
119
|
if (firstNonSsrMatchIndex === undefined) {
|
|
@@ -139,27 +141,24 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
139
141
|
const route = router.looseRoutesById[match.routeId]!
|
|
140
142
|
|
|
141
143
|
const parentMatch = router.state.matches[match.index - 1]
|
|
142
|
-
const parentContext = parentMatch?.context ?? router.options.context
|
|
144
|
+
const parentContext = parentMatch?.context ?? router.options.context ?? {}
|
|
143
145
|
|
|
144
146
|
// `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed
|
|
145
147
|
// so run it again and merge route context
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
navigate
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
matches,
|
|
159
|
-
}
|
|
160
|
-
match.__routeContext =
|
|
161
|
-
route.options.context(contextFnContext) ?? undefined
|
|
148
|
+
const contextFnContext: RouteContextOptions<any, any, any, any> = {
|
|
149
|
+
deps: match.loaderDeps,
|
|
150
|
+
params: match.params,
|
|
151
|
+
context: parentContext,
|
|
152
|
+
location: router.state.location,
|
|
153
|
+
navigate: (opts: any) =>
|
|
154
|
+
router.navigate({ ...opts, _fromLocation: router.state.location }),
|
|
155
|
+
buildLocation: router.buildLocation,
|
|
156
|
+
cause: match.cause,
|
|
157
|
+
abortController: match.abortController,
|
|
158
|
+
preload: false,
|
|
159
|
+
matches,
|
|
162
160
|
}
|
|
161
|
+
match.__routeContext = route.options.context?.(contextFnContext) ?? {}
|
|
163
162
|
|
|
164
163
|
match.context = {
|
|
165
164
|
...parentContext,
|
|
@@ -187,11 +186,11 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
187
186
|
|
|
188
187
|
const isSpaMode = matches[matches.length - 1]!.id !== lastMatchId
|
|
189
188
|
const hasSsrFalseMatches = matches.some((m) => m.ssr === false)
|
|
190
|
-
// all matches have data from the server
|
|
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()
|
|
191
190
|
if (!hasSsrFalseMatches && !isSpaMode) {
|
|
192
191
|
matches.forEach((match) => {
|
|
193
|
-
// remove the
|
|
194
|
-
match.
|
|
192
|
+
// remove the _dehydrate flag since we won't run router.load() which would remove it
|
|
193
|
+
match._dehydrated = undefined
|
|
195
194
|
})
|
|
196
195
|
return routeChunkPromise
|
|
197
196
|
}
|
|
@@ -214,7 +213,7 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
214
213
|
setMatchForcePending(match)
|
|
215
214
|
|
|
216
215
|
match._displayPending = true
|
|
217
|
-
match.
|
|
216
|
+
match.displayPendingPromise = loadPromise
|
|
218
217
|
|
|
219
218
|
loadPromise.then(() => {
|
|
220
219
|
batch(() => {
|