@tanstack/react-router 0.0.1-beta.279 → 0.0.1-beta.280
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/build/cjs/Matches.js.map +1 -1
- package/build/cjs/RouterProvider.js +1 -2
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/link.js +1 -1
- package/build/cjs/link.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +54 -91
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +56 -94
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +355 -355
- package/build/types/Matches.d.ts +0 -1
- package/build/types/fileRoute.d.ts +4 -0
- package/build/types/route.d.ts +4 -1
- package/build/types/router.d.ts +5 -3
- package/build/umd/index.development.js +56 -94
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/Matches.tsx +0 -1
- package/src/RouterProvider.tsx +1 -2
- package/src/link.tsx +1 -1
- package/src/route.ts +4 -10
- package/src/router.ts +86 -123
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.280",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@tanstack/store": "^0.1.3",
|
|
45
45
|
"tiny-invariant": "^1.3.1",
|
|
46
46
|
"tiny-warning": "^1.0.3",
|
|
47
|
-
"@tanstack/history": "0.0.1-beta.
|
|
47
|
+
"@tanstack/history": "0.0.1-beta.280"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "rollup --config rollup.config.js"
|
package/src/Matches.tsx
CHANGED
|
@@ -40,7 +40,6 @@ export interface RouteMatch<
|
|
|
40
40
|
search: FullSearchSchema<TRouteTree> &
|
|
41
41
|
RouteById<TRouteTree, TRouteId>['types']['fullSearchSchema']
|
|
42
42
|
fetchCount: number
|
|
43
|
-
shouldReloadDeps: any
|
|
44
43
|
abortController: AbortController
|
|
45
44
|
cause: 'preload' | 'enter' | 'stay'
|
|
46
45
|
loaderDeps: RouteById<TRouteTree, TRouteId>['types']['loaderDeps']
|
package/src/RouterProvider.tsx
CHANGED
|
@@ -187,7 +187,6 @@ function Transitioner() {
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
-
router.pendingMatches = []
|
|
191
190
|
|
|
192
191
|
router.__store.setState((s) => ({
|
|
193
192
|
...s,
|
|
@@ -217,7 +216,7 @@ export function getRouteMatch<TRouteTree extends AnyRoute>(
|
|
|
217
216
|
id: string,
|
|
218
217
|
): undefined | RouteMatch<TRouteTree> {
|
|
219
218
|
return [
|
|
220
|
-
...state.
|
|
219
|
+
...state.cachedMatches,
|
|
221
220
|
...(state.pendingMatches ?? []),
|
|
222
221
|
...state.matches,
|
|
223
222
|
].find((d) => d.id === id)
|
package/src/link.tsx
CHANGED
|
@@ -433,7 +433,7 @@ export function useLinkProps<
|
|
|
433
433
|
: true
|
|
434
434
|
const searchTest =
|
|
435
435
|
activeOptions?.includeSearch ?? true
|
|
436
|
-
? deepEqual(s.location.search, next.search,
|
|
436
|
+
? deepEqual(s.location.search, next.search, !activeOptions?.exact)
|
|
437
437
|
: true
|
|
438
438
|
|
|
439
439
|
// The final "active" test
|
package/src/route.ts
CHANGED
|
@@ -99,16 +99,6 @@ export type BaseRouteOptions<
|
|
|
99
99
|
> = RoutePathOptions<TCustomId, TPath> & {
|
|
100
100
|
getParentRoute: () => TParentRoute
|
|
101
101
|
validateSearch?: SearchSchemaValidator<TSearchSchema>
|
|
102
|
-
shouldReload?:
|
|
103
|
-
| boolean
|
|
104
|
-
| ((
|
|
105
|
-
match: LoaderFnContext<
|
|
106
|
-
TAllParams,
|
|
107
|
-
TFullSearchSchema,
|
|
108
|
-
TAllContext,
|
|
109
|
-
TRouteContext
|
|
110
|
-
>,
|
|
111
|
-
) => any)
|
|
112
102
|
} & (keyof PickRequired<RouteContext> extends never
|
|
113
103
|
? // This async function is called before a route is loaded.
|
|
114
104
|
// If an error is thrown here, the route's loader will not be called.
|
|
@@ -187,6 +177,10 @@ export type UpdatableRouteOptions<
|
|
|
187
177
|
pendingComponent?: RouteComponent
|
|
188
178
|
pendingMs?: number
|
|
189
179
|
pendingMinMs?: number
|
|
180
|
+
staleTime?: number
|
|
181
|
+
gcTime?: number
|
|
182
|
+
preloadStaleTime?: number
|
|
183
|
+
preloadGcTime?: number
|
|
190
184
|
// Filter functions that can manipulate search params *before* they are passed to links and navigate
|
|
191
185
|
// calls that match this route.
|
|
192
186
|
preSearchFilters?: SearchFilter<TFullSearchSchema>[]
|
package/src/router.ts
CHANGED
|
@@ -111,7 +111,10 @@ export interface RouterOptions<
|
|
|
111
111
|
defaultPendingComponent?: RouteComponent
|
|
112
112
|
defaultPendingMs?: number
|
|
113
113
|
defaultPendingMinMs?: number
|
|
114
|
-
|
|
114
|
+
defaultStaleTime?: number
|
|
115
|
+
defaultPreloadStaleTime?: number
|
|
116
|
+
defaultPreloadGcTime?: number
|
|
117
|
+
defaultGcTime?: number
|
|
115
118
|
caseSensitive?: boolean
|
|
116
119
|
routeTree?: TRouteTree
|
|
117
120
|
basepath?: string
|
|
@@ -131,7 +134,7 @@ export interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
|
|
|
131
134
|
isTransitioning: boolean
|
|
132
135
|
matches: RouteMatch<TRouteTree>[]
|
|
133
136
|
pendingMatches?: RouteMatch<TRouteTree>[]
|
|
134
|
-
|
|
137
|
+
cachedMatches: RouteMatch<TRouteTree>[]
|
|
135
138
|
location: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
136
139
|
resolvedLocation: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
137
140
|
lastUpdated: number
|
|
@@ -221,7 +224,6 @@ export class Router<
|
|
|
221
224
|
navigateTimeout: Timeout | null = null
|
|
222
225
|
latestLoadPromise: Promise<void> = Promise.resolve()
|
|
223
226
|
subscribers = new Set<RouterListener<RouterEvent>>()
|
|
224
|
-
pendingMatches: AnyRouteMatch[] = []
|
|
225
227
|
injectedHtml: InjectedHtmlEntry[] = []
|
|
226
228
|
dehydratedData?: TDehydrated
|
|
227
229
|
|
|
@@ -663,7 +665,6 @@ export class Router<
|
|
|
663
665
|
routeContext: undefined!,
|
|
664
666
|
context: undefined!,
|
|
665
667
|
abortController: new AbortController(),
|
|
666
|
-
shouldReloadDeps: undefined,
|
|
667
668
|
fetchCount: 0,
|
|
668
669
|
cause,
|
|
669
670
|
loaderDeps,
|
|
@@ -984,15 +985,18 @@ export class Router<
|
|
|
984
985
|
let firstBadMatchIndex: number | undefined
|
|
985
986
|
|
|
986
987
|
const updateMatch = (match: AnyRouteMatch) => {
|
|
987
|
-
// const isPreload = this.state.
|
|
988
|
+
// const isPreload = this.state.cachedMatches.find((d) => d.id === match.id)
|
|
988
989
|
const isPending = this.state.pendingMatches?.find(
|
|
989
990
|
(d) => d.id === match.id,
|
|
990
991
|
)
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
992
|
+
|
|
993
|
+
const isMatched = this.state.matches.find((d) => d.id === match.id)
|
|
994
|
+
|
|
995
|
+
const matchesKey = isPending
|
|
996
|
+
? 'pendingMatches'
|
|
997
|
+
: isMatched
|
|
998
|
+
? 'matches'
|
|
999
|
+
: 'cachedMatches'
|
|
996
1000
|
|
|
997
1001
|
this.__store.setState((s) => ({
|
|
998
1002
|
...s,
|
|
@@ -1149,89 +1153,33 @@ export class Router<
|
|
|
1149
1153
|
cause: preload ? 'preload' : match.cause,
|
|
1150
1154
|
}
|
|
1151
1155
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
const shouldReloadFn = route.options.shouldReload
|
|
1156
|
-
|
|
1157
|
-
let shouldReloadDeps =
|
|
1158
|
-
typeof shouldReloadFn === 'function'
|
|
1159
|
-
? shouldReloadFn(loaderContext)
|
|
1160
|
-
: !!(shouldReloadFn ?? true)
|
|
1161
|
-
|
|
1162
|
-
const compareDeps = () => {
|
|
1163
|
-
if (typeof shouldReloadDeps === 'object') {
|
|
1164
|
-
// compare the deps to see if they've changed
|
|
1165
|
-
shouldLoad = !deepEqual(
|
|
1166
|
-
shouldReloadDeps,
|
|
1167
|
-
match.shouldReloadDeps,
|
|
1168
|
-
)
|
|
1169
|
-
} else {
|
|
1170
|
-
shouldLoad = !!shouldReloadDeps
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
// If it's the first preload, or the route is entering, or we're
|
|
1175
|
-
// invalidating, we definitely need to load the route
|
|
1176
|
-
if (invalidate) {
|
|
1177
|
-
// Change nothing, we need to load the route
|
|
1178
|
-
} else if (preload) {
|
|
1179
|
-
if (!match.fetchCount) {
|
|
1180
|
-
// Change nothing, we need to preload the route
|
|
1181
|
-
} else {
|
|
1182
|
-
compareDeps()
|
|
1183
|
-
}
|
|
1184
|
-
} else if (match.cause === 'enter') {
|
|
1185
|
-
if (!match.fetchCount) {
|
|
1186
|
-
// Change nothing, we 100% need to load the route
|
|
1187
|
-
} else {
|
|
1188
|
-
compareDeps()
|
|
1189
|
-
}
|
|
1190
|
-
} else {
|
|
1191
|
-
compareDeps()
|
|
1156
|
+
if (match.fetchCount && match.status === 'success') {
|
|
1157
|
+
resolve()
|
|
1192
1158
|
}
|
|
1193
1159
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1160
|
+
// Otherwise, load the route
|
|
1161
|
+
matches[index] = match = {
|
|
1162
|
+
...match,
|
|
1163
|
+
isFetching: true,
|
|
1164
|
+
fetchCount: match.fetchCount + 1,
|
|
1199
1165
|
}
|
|
1200
1166
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
if (!shouldLoad) {
|
|
1205
|
-
loadPromise = Promise.resolve(match.loaderData)
|
|
1206
|
-
} else {
|
|
1207
|
-
if (match.fetchCount && match.status === 'success') {
|
|
1208
|
-
resolve()
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
// Otherwise, load the route
|
|
1212
|
-
matches[index] = match = {
|
|
1213
|
-
...match,
|
|
1214
|
-
isFetching: true,
|
|
1215
|
-
fetchCount: match.fetchCount + 1,
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
const componentsPromise = Promise.all(
|
|
1219
|
-
componentTypes.map(async (type) => {
|
|
1220
|
-
const component = route.options[type]
|
|
1167
|
+
const componentsPromise = Promise.all(
|
|
1168
|
+
componentTypes.map(async (type) => {
|
|
1169
|
+
const component = route.options[type]
|
|
1221
1170
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1171
|
+
if ((component as any)?.preload) {
|
|
1172
|
+
await (component as any).preload()
|
|
1173
|
+
}
|
|
1174
|
+
}),
|
|
1175
|
+
)
|
|
1227
1176
|
|
|
1228
|
-
|
|
1177
|
+
const loaderPromise = route.options.loader?.(loaderContext)
|
|
1229
1178
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
}
|
|
1179
|
+
loadPromise = Promise.all([
|
|
1180
|
+
componentsPromise,
|
|
1181
|
+
loaderPromise,
|
|
1182
|
+
]).then((d) => d[1])
|
|
1235
1183
|
}
|
|
1236
1184
|
|
|
1237
1185
|
matches[index] = match = {
|
|
@@ -1280,25 +1228,28 @@ export class Router<
|
|
|
1280
1228
|
error,
|
|
1281
1229
|
status: 'error',
|
|
1282
1230
|
isFetching: false,
|
|
1283
|
-
updatedAt: Date.now(),
|
|
1284
|
-
}
|
|
1285
|
-
} finally {
|
|
1286
|
-
// If we showed the pending component, that means
|
|
1287
|
-
// we already moved the pendingMatches to the matches
|
|
1288
|
-
// state, so we need to update that specific match
|
|
1289
|
-
if (didShowPending && pendingMinMs && match.showPending) {
|
|
1290
|
-
updateMatch(match)
|
|
1291
1231
|
}
|
|
1292
1232
|
}
|
|
1293
1233
|
|
|
1294
1234
|
updateMatch(match)
|
|
1295
1235
|
}
|
|
1296
1236
|
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1237
|
+
// This is where all of the stale-while-revalidate magic happens
|
|
1238
|
+
const age = Date.now() - match.updatedAt
|
|
1239
|
+
|
|
1240
|
+
let staleAge = preload
|
|
1241
|
+
? route.options.preloadStaleTime ??
|
|
1242
|
+
this.options.defaultPreloadStaleTime ??
|
|
1243
|
+
30_000 // 30 seconds for preloads by default
|
|
1244
|
+
: route.options.staleTime ?? this.options.defaultStaleTime ?? 0
|
|
1245
|
+
|
|
1246
|
+
if (match.status === 'success') {
|
|
1247
|
+
// Background Fetching, no need to wait
|
|
1248
|
+
if (age > staleAge) {
|
|
1249
|
+
fetch()
|
|
1250
|
+
}
|
|
1300
1251
|
} else {
|
|
1301
|
-
// Critical Fetching
|
|
1252
|
+
// Critical Fetching, we need to await
|
|
1302
1253
|
|
|
1303
1254
|
// If we need to potentially show the pending component,
|
|
1304
1255
|
// start a timer to show it after the pendingMs
|
|
@@ -1320,9 +1271,6 @@ export class Router<
|
|
|
1320
1271
|
await fetch()
|
|
1321
1272
|
}
|
|
1322
1273
|
|
|
1323
|
-
resolve()
|
|
1324
|
-
// No Fetching
|
|
1325
|
-
|
|
1326
1274
|
resolve()
|
|
1327
1275
|
}),
|
|
1328
1276
|
)
|
|
@@ -1358,15 +1306,23 @@ export class Router<
|
|
|
1358
1306
|
const previousMatches = this.state.matches
|
|
1359
1307
|
|
|
1360
1308
|
this.__store.batch(() => {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1309
|
+
// This is where all of the garbage collection magic happens
|
|
1310
|
+
this.__store.setState((s) => {
|
|
1311
|
+
return {
|
|
1312
|
+
...s,
|
|
1313
|
+
cachedMatches: s.cachedMatches.filter((d) => {
|
|
1314
|
+
const route = this.looseRoutesById[d.routeId]!
|
|
1315
|
+
|
|
1316
|
+
return (
|
|
1317
|
+
d.status !== 'error' &&
|
|
1318
|
+
Date.now() - d.updatedAt <
|
|
1319
|
+
(route.options.gcTime ??
|
|
1320
|
+
this.options.defaultGcTime ??
|
|
1321
|
+
5 * 60 * 1000)
|
|
1322
|
+
)
|
|
1323
|
+
}),
|
|
1324
|
+
}
|
|
1325
|
+
})
|
|
1370
1326
|
|
|
1371
1327
|
// Match the routes
|
|
1372
1328
|
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
@@ -1374,12 +1330,13 @@ export class Router<
|
|
|
1374
1330
|
})
|
|
1375
1331
|
|
|
1376
1332
|
// Ingest the new matches
|
|
1333
|
+
// If a cached moved to pendingMatches, remove it from cachedMatches
|
|
1377
1334
|
this.__store.setState((s) => ({
|
|
1378
1335
|
...s,
|
|
1379
1336
|
isLoading: true,
|
|
1380
1337
|
location: next,
|
|
1381
1338
|
pendingMatches,
|
|
1382
|
-
|
|
1339
|
+
cachedMatches: s.cachedMatches.filter((d) => {
|
|
1383
1340
|
return !pendingMatches.find((e) => e.id === d.id)
|
|
1384
1341
|
}),
|
|
1385
1342
|
}))
|
|
@@ -1403,29 +1360,35 @@ export class Router<
|
|
|
1403
1360
|
return latestPromise
|
|
1404
1361
|
}
|
|
1405
1362
|
|
|
1406
|
-
const
|
|
1407
|
-
(
|
|
1363
|
+
const exitingMatches = previousMatches.filter(
|
|
1364
|
+
(match) => !pendingMatches.find((d) => d.id === match.id),
|
|
1408
1365
|
)
|
|
1409
|
-
const
|
|
1410
|
-
(
|
|
1366
|
+
const enteringMatches = pendingMatches.filter(
|
|
1367
|
+
(match) => !previousMatches.find((d) => d.id === match.id),
|
|
1411
1368
|
)
|
|
1412
|
-
const
|
|
1413
|
-
|
|
1369
|
+
const stayingMatches = previousMatches.filter((match) =>
|
|
1370
|
+
pendingMatches.find((d) => d.id === match.id),
|
|
1414
1371
|
)
|
|
1415
1372
|
|
|
1373
|
+
// Commit the pending matches. If a previous match was
|
|
1374
|
+
// removed, place it in the cachedMatches
|
|
1416
1375
|
this.__store.setState((s) => ({
|
|
1417
1376
|
...s,
|
|
1418
1377
|
isLoading: false,
|
|
1419
1378
|
matches: pendingMatches,
|
|
1420
1379
|
pendingMatches: undefined,
|
|
1380
|
+
cachedMatches: [
|
|
1381
|
+
...s.cachedMatches,
|
|
1382
|
+
...exitingMatches.filter((d) => d.status !== 'error'),
|
|
1383
|
+
],
|
|
1421
1384
|
}))
|
|
1422
1385
|
|
|
1423
1386
|
//
|
|
1424
1387
|
;(
|
|
1425
1388
|
[
|
|
1426
|
-
[
|
|
1427
|
-
[
|
|
1428
|
-
[
|
|
1389
|
+
[exitingMatches, 'onLeave'],
|
|
1390
|
+
[enteringMatches, 'onEnter'],
|
|
1391
|
+
[stayingMatches, 'onStay'],
|
|
1429
1392
|
] as const
|
|
1430
1393
|
).forEach(([matches, hook]) => {
|
|
1431
1394
|
matches.forEach((match) => {
|
|
@@ -1469,7 +1432,7 @@ export class Router<
|
|
|
1469
1432
|
[
|
|
1470
1433
|
...this.state.matches,
|
|
1471
1434
|
...(this.state.pendingMatches ?? []),
|
|
1472
|
-
...this.state.
|
|
1435
|
+
...this.state.cachedMatches,
|
|
1473
1436
|
]?.map((d) => [d.id, true]),
|
|
1474
1437
|
)
|
|
1475
1438
|
|
|
@@ -1478,7 +1441,7 @@ export class Router<
|
|
|
1478
1441
|
if (!loadedMatchIds[match.id]) {
|
|
1479
1442
|
this.__store.setState((s) => ({
|
|
1480
1443
|
...s,
|
|
1481
|
-
|
|
1444
|
+
cachedMatches: [...(s.cachedMatches as any), match],
|
|
1482
1445
|
}))
|
|
1483
1446
|
}
|
|
1484
1447
|
})
|
|
@@ -1661,7 +1624,7 @@ export function getInitialRouterState(
|
|
|
1661
1624
|
location,
|
|
1662
1625
|
matches: [],
|
|
1663
1626
|
pendingMatches: [],
|
|
1664
|
-
|
|
1627
|
+
cachedMatches: [],
|
|
1665
1628
|
lastUpdated: Date.now(),
|
|
1666
1629
|
}
|
|
1667
1630
|
}
|