@tanstack/router-core 0.0.1-alpha.8 → 0.0.1-alpha.9
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/packages/router-core/src/routeMatch.js +6 -5
- package/build/cjs/packages/router-core/src/routeMatch.js.map +1 -1
- package/build/cjs/packages/router-core/src/router.js +43 -26
- package/build/cjs/packages/router-core/src/router.js.map +1 -1
- package/build/esm/index.js +49 -31
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +134 -134
- package/build/types/index.d.ts +15 -6
- package/build/umd/index.development.js +49 -31
- 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 +1 -1
- package/src/link.ts +3 -1
- package/src/routeMatch.ts +11 -7
- package/src/router.ts +52 -32
package/package.json
CHANGED
package/src/link.ts
CHANGED
|
@@ -220,8 +220,10 @@ export type LinkOptions<
|
|
|
220
220
|
activeOptions?: ActiveOptions
|
|
221
221
|
// If set, will preload the linked route on hover and cache it for this many milliseconds in hopes that the user will eventually navigate there.
|
|
222
222
|
preload?: false | 'intent'
|
|
223
|
-
// When preloaded
|
|
223
|
+
// When preloaded, the preloaded result will be considered "fresh" for this duration in milliseconds
|
|
224
224
|
preloadMaxAge?: number
|
|
225
|
+
// When preloaded and subsequently inactive, the preloaded result will remain in memory for this duration in milliseconds
|
|
226
|
+
preloadGcMaxAge?: number
|
|
225
227
|
// Delay intent preloading by this many milliseconds. If the intent exits before this delay, the preload will be cancelled.
|
|
226
228
|
preloadDelay?: number
|
|
227
229
|
// If true, will render the link without the href attribute
|
package/src/routeMatch.ts
CHANGED
|
@@ -30,6 +30,7 @@ export interface RouteMatch<
|
|
|
30
30
|
routeLoaderData: TRouteInfo['routeLoaderData']
|
|
31
31
|
isFetching: boolean
|
|
32
32
|
isPending: boolean
|
|
33
|
+
invalidAt: number
|
|
33
34
|
__: {
|
|
34
35
|
element?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
|
|
35
36
|
errorElement?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
|
|
@@ -60,7 +61,7 @@ export interface RouteMatch<
|
|
|
60
61
|
resolve: () => void
|
|
61
62
|
}
|
|
62
63
|
cancel: () => void
|
|
63
|
-
load: () => Promise<void>
|
|
64
|
+
load: (opts?: { maxAge?: number }) => Promise<void>
|
|
64
65
|
invalidate: () => void
|
|
65
66
|
hasLoaders: () => boolean
|
|
66
67
|
}
|
|
@@ -97,13 +98,10 @@ export function createRouteMatch<
|
|
|
97
98
|
isPending: false,
|
|
98
99
|
isFetching: false,
|
|
99
100
|
isInvalid: false,
|
|
101
|
+
invalidAt: Infinity,
|
|
100
102
|
getIsInvalid: () => {
|
|
101
103
|
const now = Date.now()
|
|
102
|
-
|
|
103
|
-
routeMatch.options.loaderMaxAge ??
|
|
104
|
-
router.options.defaultLoaderMaxAge ??
|
|
105
|
-
0
|
|
106
|
-
return routeMatch.isInvalid || routeMatch.updatedAt! + maxAge < now
|
|
104
|
+
return routeMatch.isInvalid || routeMatch.invalidAt < now
|
|
107
105
|
},
|
|
108
106
|
__: {
|
|
109
107
|
abortController: new AbortController(),
|
|
@@ -212,7 +210,7 @@ export function createRouteMatch<
|
|
|
212
210
|
elementTypes.some((d) => typeof route.options[d] === 'function')
|
|
213
211
|
)
|
|
214
212
|
},
|
|
215
|
-
load: async () => {
|
|
213
|
+
load: async (opts) => {
|
|
216
214
|
const id = '' + Date.now() + Math.random()
|
|
217
215
|
routeMatch.__.latestId = id
|
|
218
216
|
|
|
@@ -298,6 +296,12 @@ export function createRouteMatch<
|
|
|
298
296
|
routeMatch.error = undefined
|
|
299
297
|
routeMatch.status = 'success'
|
|
300
298
|
routeMatch.updatedAt = Date.now()
|
|
299
|
+
routeMatch.invalidAt =
|
|
300
|
+
routeMatch.updatedAt +
|
|
301
|
+
(opts?.maxAge ??
|
|
302
|
+
routeMatch.options.loaderMaxAge ??
|
|
303
|
+
router.options.defaultLoaderMaxAge ??
|
|
304
|
+
0)
|
|
301
305
|
} catch (err) {
|
|
302
306
|
if (id !== routeMatch.__.latestId) {
|
|
303
307
|
return routeMatch.__.loaderPromise
|
package/src/router.ts
CHANGED
|
@@ -81,9 +81,10 @@ export interface RouterOptions<TRouteConfig extends AnyRouteConfig> {
|
|
|
81
81
|
stringifySearch?: SearchSerializer
|
|
82
82
|
parseSearch?: SearchParser
|
|
83
83
|
filterRoutes?: FilterRoutesFn
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
defaultPreload?: false | 'intent'
|
|
85
|
+
defaultPreloadMaxAge?: number
|
|
86
|
+
defaultPreloadGcMaxAge?: number
|
|
87
|
+
defaultPreloadDelay?: number
|
|
87
88
|
useErrorBoundary?: boolean
|
|
88
89
|
defaultElement?: GetFrameworkGeneric<'Element'>
|
|
89
90
|
defaultErrorElement?: GetFrameworkGeneric<'Element'>
|
|
@@ -227,9 +228,10 @@ export interface Router<
|
|
|
227
228
|
getRoute: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
228
229
|
id: TId,
|
|
229
230
|
) => Route<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
230
|
-
loadRoute: (
|
|
231
|
+
loadRoute: (navigateOpts: BuildNextOptions) => Promise<RouteMatch[]>
|
|
232
|
+
preloadRoute: (
|
|
231
233
|
navigateOpts: BuildNextOptions,
|
|
232
|
-
loaderOpts: { maxAge
|
|
234
|
+
loaderOpts: { maxAge?: number; gcMaxAge?: number },
|
|
233
235
|
) => Promise<RouteMatch[]>
|
|
234
236
|
matchRoutes: (
|
|
235
237
|
pathname: string,
|
|
@@ -238,8 +240,8 @@ export interface Router<
|
|
|
238
240
|
loadMatches: (
|
|
239
241
|
resolvedMatches: RouteMatch[],
|
|
240
242
|
loaderOpts?: { withPending?: boolean } & (
|
|
241
|
-
| { preload: true; maxAge: number }
|
|
242
|
-
| { preload?: false; maxAge?: never }
|
|
243
|
+
| { preload: true; maxAge: number; gcMaxAge: number }
|
|
244
|
+
| { preload?: false; maxAge?: never; gcMaxAge?: never }
|
|
243
245
|
),
|
|
244
246
|
) => Promise<void>
|
|
245
247
|
invalidateRoute: (opts: MatchLocation) => void
|
|
@@ -289,7 +291,8 @@ export function createRouter<
|
|
|
289
291
|
const originalOptions = {
|
|
290
292
|
defaultLoaderGcMaxAge: 5 * 60 * 1000,
|
|
291
293
|
defaultLoaderMaxAge: 0,
|
|
292
|
-
|
|
294
|
+
defaultPreloadMaxAge: 2000,
|
|
295
|
+
defaultPreloadDelay: 50,
|
|
293
296
|
...userOptions,
|
|
294
297
|
stringifySearch: userOptions?.stringifySearch ?? defaultStringifySearch,
|
|
295
298
|
parseSearch: userOptions?.parseSearch ?? defaultParseSearch,
|
|
@@ -782,17 +785,32 @@ export function createRouter<
|
|
|
782
785
|
})
|
|
783
786
|
},
|
|
784
787
|
|
|
785
|
-
loadRoute: async (
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
788
|
+
loadRoute: async (navigateOpts = router.location) => {
|
|
789
|
+
const next = router.buildNext(navigateOpts)
|
|
790
|
+
const matches = router.matchRoutes(next.pathname, {
|
|
791
|
+
strictParseParams: true,
|
|
792
|
+
})
|
|
793
|
+
await router.loadMatches(matches)
|
|
794
|
+
return matches
|
|
795
|
+
},
|
|
796
|
+
|
|
797
|
+
preloadRoute: async (navigateOpts = router.location, loaderOpts) => {
|
|
789
798
|
const next = router.buildNext(navigateOpts)
|
|
790
799
|
const matches = router.matchRoutes(next.pathname, {
|
|
791
800
|
strictParseParams: true,
|
|
792
801
|
})
|
|
793
802
|
await router.loadMatches(matches, {
|
|
794
803
|
preload: true,
|
|
795
|
-
maxAge:
|
|
804
|
+
maxAge:
|
|
805
|
+
loaderOpts.maxAge ??
|
|
806
|
+
router.options.defaultPreloadMaxAge ??
|
|
807
|
+
router.options.defaultLoaderMaxAge ??
|
|
808
|
+
0,
|
|
809
|
+
gcMaxAge:
|
|
810
|
+
loaderOpts.gcMaxAge ??
|
|
811
|
+
router.options.defaultPreloadGcMaxAge ??
|
|
812
|
+
router.options.defaultLoaderGcMaxAge ??
|
|
813
|
+
0,
|
|
796
814
|
})
|
|
797
815
|
return matches
|
|
798
816
|
},
|
|
@@ -905,25 +923,23 @@ export function createRouter<
|
|
|
905
923
|
|
|
906
924
|
loadMatches: async (resolvedMatches, loaderOpts) => {
|
|
907
925
|
const now = Date.now()
|
|
926
|
+
const minMaxAge = loaderOpts?.preload
|
|
927
|
+
? Math.max(loaderOpts?.maxAge, loaderOpts?.gcMaxAge)
|
|
928
|
+
: 0
|
|
908
929
|
|
|
909
930
|
const matchPromises = resolvedMatches.map(async (match) => {
|
|
910
931
|
// Validate the match (loads search params etc)
|
|
911
932
|
match.__.validate()
|
|
912
933
|
|
|
913
|
-
// // If the match doesn't have a loader, don't attempt to load it
|
|
914
|
-
// if (!match.hasLoaders()) {
|
|
915
|
-
// return
|
|
916
|
-
// }
|
|
917
|
-
|
|
918
934
|
// If this is a preload, add it to the preload cache
|
|
919
|
-
if (loaderOpts?.preload &&
|
|
935
|
+
if (loaderOpts?.preload && minMaxAge > 0) {
|
|
920
936
|
// If the match is currently active, don't preload it
|
|
921
937
|
if (router.state.matches.find((d) => d.matchId === match.matchId)) {
|
|
922
938
|
return
|
|
923
939
|
}
|
|
924
940
|
|
|
925
941
|
router.matchCache[match.matchId] = {
|
|
926
|
-
gc: now + loaderOpts.
|
|
942
|
+
gc: now + loaderOpts.gcMaxAge,
|
|
927
943
|
match,
|
|
928
944
|
}
|
|
929
945
|
}
|
|
@@ -934,7 +950,9 @@ export function createRouter<
|
|
|
934
950
|
match.status === 'error' ||
|
|
935
951
|
match.status === 'idle'
|
|
936
952
|
) {
|
|
937
|
-
|
|
953
|
+
const maxAge = loaderOpts?.preload ? loaderOpts?.maxAge : undefined
|
|
954
|
+
|
|
955
|
+
match.load({ maxAge })
|
|
938
956
|
}
|
|
939
957
|
|
|
940
958
|
if (match.status === 'loading') {
|
|
@@ -1053,6 +1071,7 @@ export function createRouter<
|
|
|
1053
1071
|
activeOptions,
|
|
1054
1072
|
preload,
|
|
1055
1073
|
preloadMaxAge: userPreloadMaxAge,
|
|
1074
|
+
preloadGcMaxAge: userPreloadGcMaxAge,
|
|
1056
1075
|
preloadDelay: userPreloadDelay,
|
|
1057
1076
|
disabled,
|
|
1058
1077
|
}) => {
|
|
@@ -1081,14 +1100,9 @@ export function createRouter<
|
|
|
1081
1100
|
|
|
1082
1101
|
const next = router.buildNext(nextOpts)
|
|
1083
1102
|
|
|
1084
|
-
preload = preload ?? router.options.
|
|
1085
|
-
const preloadMaxAge =
|
|
1086
|
-
userPreloadMaxAge ??
|
|
1087
|
-
router.options.defaultLinkPreloadMaxAge ??
|
|
1088
|
-
router.options.defaultLoaderGcMaxAge ??
|
|
1089
|
-
0
|
|
1103
|
+
preload = preload ?? router.options.defaultPreload
|
|
1090
1104
|
const preloadDelay =
|
|
1091
|
-
userPreloadDelay ?? router.options.
|
|
1105
|
+
userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0
|
|
1092
1106
|
|
|
1093
1107
|
// Compare path/hash for matches
|
|
1094
1108
|
const pathIsEqual = router.state.location.pathname === next.pathname
|
|
@@ -1126,22 +1140,28 @@ export function createRouter<
|
|
|
1126
1140
|
|
|
1127
1141
|
// The click handler
|
|
1128
1142
|
const handleFocus = (e: MouseEvent) => {
|
|
1129
|
-
if (preload
|
|
1130
|
-
router.
|
|
1143
|
+
if (preload) {
|
|
1144
|
+
router.preloadRoute(nextOpts, {
|
|
1145
|
+
maxAge: userPreloadMaxAge,
|
|
1146
|
+
gcMaxAge: userPreloadGcMaxAge,
|
|
1147
|
+
})
|
|
1131
1148
|
}
|
|
1132
1149
|
}
|
|
1133
1150
|
|
|
1134
1151
|
const handleEnter = (e: MouseEvent) => {
|
|
1135
1152
|
const target = (e.target || {}) as LinkCurrentTargetElement
|
|
1136
1153
|
|
|
1137
|
-
if (preload
|
|
1154
|
+
if (preload) {
|
|
1138
1155
|
if (target.preloadTimeout) {
|
|
1139
1156
|
return
|
|
1140
1157
|
}
|
|
1141
1158
|
|
|
1142
1159
|
target.preloadTimeout = setTimeout(() => {
|
|
1143
1160
|
target.preloadTimeout = null
|
|
1144
|
-
router.
|
|
1161
|
+
router.preloadRoute(nextOpts, {
|
|
1162
|
+
maxAge: userPreloadMaxAge,
|
|
1163
|
+
gcMaxAge: userPreloadGcMaxAge,
|
|
1164
|
+
})
|
|
1145
1165
|
}, preloadDelay)
|
|
1146
1166
|
}
|
|
1147
1167
|
}
|