@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/build/types/Matches.d.ts
CHANGED
|
@@ -23,7 +23,6 @@ export interface RouteMatch<TRouteTree extends AnyRoute = AnyRoute, TRouteId ext
|
|
|
23
23
|
context: RouteById<TRouteTree, TRouteId>['types']['allContext'];
|
|
24
24
|
search: FullSearchSchema<TRouteTree> & RouteById<TRouteTree, TRouteId>['types']['fullSearchSchema'];
|
|
25
25
|
fetchCount: number;
|
|
26
|
-
shouldReloadDeps: any;
|
|
27
26
|
abortController: AbortController;
|
|
28
27
|
cause: 'preload' | 'enter' | 'stay';
|
|
29
28
|
loaderDeps: RouteById<TRouteTree, TRouteId>['types']['loaderDeps'];
|
|
@@ -23,6 +23,10 @@ export declare class FileRoute<TFilePath extends keyof FileRoutesByPath, TParent
|
|
|
23
23
|
pendingComponent?: import("./route").RouteComponent<any> | undefined;
|
|
24
24
|
pendingMs?: number | undefined;
|
|
25
25
|
pendingMinMs?: number | undefined;
|
|
26
|
+
staleTime?: number | undefined;
|
|
27
|
+
gcTime?: number | undefined;
|
|
28
|
+
preloadStaleTime?: number | undefined;
|
|
29
|
+
preloadGcTime?: number | undefined;
|
|
26
30
|
preSearchFilters?: import("./route").SearchFilter<TFullSearchSchema, TFullSearchSchema>[] | undefined;
|
|
27
31
|
postSearchFilters?: import("./route").SearchFilter<TFullSearchSchema, TFullSearchSchema>[] | undefined;
|
|
28
32
|
onError?: ((err: any) => void) | undefined;
|
package/build/types/route.d.ts
CHANGED
|
@@ -34,7 +34,6 @@ export type ParamsFallback<TPath extends string, TParams> = unknown extends TPar
|
|
|
34
34
|
export type BaseRouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TSearchSchema extends Record<string, any> = {}, TFullSearchSchema extends Record<string, any> = TSearchSchema, TParams extends AnyPathParams = {}, TAllParams = ParamsFallback<TPath, TParams>, TRouteContext extends RouteContext = RouteContext, TAllContext extends Record<string, any> = AnyContext, TLoaderDeps extends Record<string, any> = {}, TLoaderData extends any = unknown> = RoutePathOptions<TCustomId, TPath> & {
|
|
35
35
|
getParentRoute: () => TParentRoute;
|
|
36
36
|
validateSearch?: SearchSchemaValidator<TSearchSchema>;
|
|
37
|
-
shouldReload?: boolean | ((match: LoaderFnContext<TAllParams, TFullSearchSchema, TAllContext, TRouteContext>) => any);
|
|
38
37
|
} & (keyof PickRequired<RouteContext> extends never ? {
|
|
39
38
|
beforeLoad?: BeforeLoadFn<TFullSearchSchema, TParentRoute, TAllParams, TRouteContext>;
|
|
40
39
|
} : {
|
|
@@ -70,6 +69,10 @@ export type UpdatableRouteOptions<TFullSearchSchema extends Record<string, any>>
|
|
|
70
69
|
pendingComponent?: RouteComponent;
|
|
71
70
|
pendingMs?: number;
|
|
72
71
|
pendingMinMs?: number;
|
|
72
|
+
staleTime?: number;
|
|
73
|
+
gcTime?: number;
|
|
74
|
+
preloadStaleTime?: number;
|
|
75
|
+
preloadGcTime?: number;
|
|
73
76
|
preSearchFilters?: SearchFilter<TFullSearchSchema>[];
|
|
74
77
|
postSearchFilters?: SearchFilter<TFullSearchSchema>[];
|
|
75
78
|
onError?: (err: any) => void;
|
package/build/types/router.d.ts
CHANGED
|
@@ -42,7 +42,10 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TDehydrated extends
|
|
|
42
42
|
defaultPendingComponent?: RouteComponent;
|
|
43
43
|
defaultPendingMs?: number;
|
|
44
44
|
defaultPendingMinMs?: number;
|
|
45
|
-
|
|
45
|
+
defaultStaleTime?: number;
|
|
46
|
+
defaultPreloadStaleTime?: number;
|
|
47
|
+
defaultPreloadGcTime?: number;
|
|
48
|
+
defaultGcTime?: number;
|
|
46
49
|
caseSensitive?: boolean;
|
|
47
50
|
routeTree?: TRouteTree;
|
|
48
51
|
basepath?: string;
|
|
@@ -65,7 +68,7 @@ export interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
|
|
|
65
68
|
isTransitioning: boolean;
|
|
66
69
|
matches: RouteMatch<TRouteTree>[];
|
|
67
70
|
pendingMatches?: RouteMatch<TRouteTree>[];
|
|
68
|
-
|
|
71
|
+
cachedMatches: RouteMatch<TRouteTree>[];
|
|
69
72
|
location: ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
70
73
|
resolvedLocation: ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
71
74
|
lastUpdated: number;
|
|
@@ -127,7 +130,6 @@ export declare class Router<TRouteTree extends AnyRoute = AnyRoute, TDehydrated
|
|
|
127
130
|
navigateTimeout: Timeout | null;
|
|
128
131
|
latestLoadPromise: Promise<void>;
|
|
129
132
|
subscribers: Set<RouterListener<RouterEvent>>;
|
|
130
|
-
pendingMatches: AnyRouteMatch[];
|
|
131
133
|
injectedHtml: InjectedHtmlEntry[];
|
|
132
134
|
dehydratedData?: TDehydrated;
|
|
133
135
|
__store: Store<RouterState<TRouteTree>>;
|
|
@@ -1192,7 +1192,6 @@
|
|
|
1192
1192
|
}
|
|
1193
1193
|
}
|
|
1194
1194
|
}
|
|
1195
|
-
router.pendingMatches = [];
|
|
1196
1195
|
router.__store.setState(s => ({
|
|
1197
1196
|
...s,
|
|
1198
1197
|
isTransitioning: false,
|
|
@@ -1208,7 +1207,7 @@
|
|
|
1208
1207
|
return null;
|
|
1209
1208
|
}
|
|
1210
1209
|
function getRouteMatch(state, id) {
|
|
1211
|
-
return [...state.
|
|
1210
|
+
return [...state.cachedMatches, ...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
1212
1211
|
}
|
|
1213
1212
|
function useRouterState(opts) {
|
|
1214
1213
|
const router = useRouter();
|
|
@@ -1755,7 +1754,7 @@
|
|
|
1755
1754
|
// Combine the matches based on user router.options
|
|
1756
1755
|
const pathTest = activeOptions?.exact ? s.location.pathname === next.pathname : pathIsFuzzyEqual;
|
|
1757
1756
|
const hashTest = activeOptions?.includeHash ? s.location.hash === next.hash : true;
|
|
1758
|
-
const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(s.location.search, next.search,
|
|
1757
|
+
const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(s.location.search, next.search, !activeOptions?.exact) : true;
|
|
1759
1758
|
|
|
1760
1759
|
// The final "active" test
|
|
1761
1760
|
return pathTest && hashTest && searchTest;
|
|
@@ -2002,7 +2001,6 @@
|
|
|
2002
2001
|
navigateTimeout = null;
|
|
2003
2002
|
latestLoadPromise = Promise.resolve();
|
|
2004
2003
|
subscribers = new Set();
|
|
2005
|
-
pendingMatches = [];
|
|
2006
2004
|
injectedHtml = [];
|
|
2007
2005
|
|
|
2008
2006
|
// Must build in constructor
|
|
@@ -2326,7 +2324,6 @@
|
|
|
2326
2324
|
routeContext: undefined,
|
|
2327
2325
|
context: undefined,
|
|
2328
2326
|
abortController: new AbortController(),
|
|
2329
|
-
shouldReloadDeps: undefined,
|
|
2330
2327
|
fetchCount: 0,
|
|
2331
2328
|
cause,
|
|
2332
2329
|
loaderDeps
|
|
@@ -2538,9 +2535,10 @@
|
|
|
2538
2535
|
let latestPromise;
|
|
2539
2536
|
let firstBadMatchIndex;
|
|
2540
2537
|
const updateMatch = match => {
|
|
2541
|
-
// const isPreload = this.state.
|
|
2538
|
+
// const isPreload = this.state.cachedMatches.find((d) => d.id === match.id)
|
|
2542
2539
|
const isPending = this.state.pendingMatches?.find(d => d.id === match.id);
|
|
2543
|
-
const
|
|
2540
|
+
const isMatched = this.state.matches.find(d => d.id === match.id);
|
|
2541
|
+
const matchesKey = isPending ? 'pendingMatches' : isMatched ? 'matches' : 'cachedMatches';
|
|
2544
2542
|
this.__store.setState(s => ({
|
|
2545
2543
|
...s,
|
|
2546
2544
|
[matchesKey]: s[matchesKey]?.map(d => d.id === match.id ? match : d)
|
|
@@ -2665,65 +2663,24 @@
|
|
|
2665
2663
|
}),
|
|
2666
2664
|
cause: preload ? 'preload' : match.cause
|
|
2667
2665
|
};
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
let shouldLoad = true;
|
|
2671
|
-
const shouldReloadFn = route.options.shouldReload;
|
|
2672
|
-
let shouldReloadDeps = typeof shouldReloadFn === 'function' ? shouldReloadFn(loaderContext) : !!(shouldReloadFn ?? true);
|
|
2673
|
-
const compareDeps = () => {
|
|
2674
|
-
if (typeof shouldReloadDeps === 'object') {
|
|
2675
|
-
// compare the deps to see if they've changed
|
|
2676
|
-
shouldLoad = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
|
|
2677
|
-
} else {
|
|
2678
|
-
shouldLoad = !!shouldReloadDeps;
|
|
2679
|
-
}
|
|
2680
|
-
};
|
|
2681
|
-
|
|
2682
|
-
// If it's the first preload, or the route is entering, or we're
|
|
2683
|
-
// invalidating, we definitely need to load the route
|
|
2684
|
-
if (invalidate) ; else if (preload) {
|
|
2685
|
-
if (!match.fetchCount) ; else {
|
|
2686
|
-
compareDeps();
|
|
2687
|
-
}
|
|
2688
|
-
} else if (match.cause === 'enter') {
|
|
2689
|
-
if (!match.fetchCount) ; else {
|
|
2690
|
-
compareDeps();
|
|
2691
|
-
}
|
|
2692
|
-
} else {
|
|
2693
|
-
compareDeps();
|
|
2694
|
-
}
|
|
2695
|
-
if (typeof shouldReloadDeps === 'object') {
|
|
2696
|
-
matches[index] = match = {
|
|
2697
|
-
...match,
|
|
2698
|
-
shouldReloadDeps
|
|
2699
|
-
};
|
|
2666
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2667
|
+
resolve();
|
|
2700
2668
|
}
|
|
2701
2669
|
|
|
2702
|
-
//
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
}
|
|
2708
|
-
|
|
2709
|
-
|
|
2670
|
+
// Otherwise, load the route
|
|
2671
|
+
matches[index] = match = {
|
|
2672
|
+
...match,
|
|
2673
|
+
isFetching: true,
|
|
2674
|
+
fetchCount: match.fetchCount + 1
|
|
2675
|
+
};
|
|
2676
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2677
|
+
const component = route.options[type];
|
|
2678
|
+
if (component?.preload) {
|
|
2679
|
+
await component.preload();
|
|
2710
2680
|
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
...match,
|
|
2715
|
-
isFetching: true,
|
|
2716
|
-
fetchCount: match.fetchCount + 1
|
|
2717
|
-
};
|
|
2718
|
-
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2719
|
-
const component = route.options[type];
|
|
2720
|
-
if (component?.preload) {
|
|
2721
|
-
await component.preload();
|
|
2722
|
-
}
|
|
2723
|
-
}));
|
|
2724
|
-
const loaderPromise = route.options.loader?.(loaderContext);
|
|
2725
|
-
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2726
|
-
}
|
|
2681
|
+
}));
|
|
2682
|
+
const loaderPromise = route.options.loader?.(loaderContext);
|
|
2683
|
+
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2727
2684
|
}
|
|
2728
2685
|
matches[index] = match = {
|
|
2729
2686
|
...match,
|
|
@@ -2762,24 +2719,23 @@
|
|
|
2762
2719
|
...match,
|
|
2763
2720
|
error,
|
|
2764
2721
|
status: 'error',
|
|
2765
|
-
isFetching: false
|
|
2766
|
-
updatedAt: Date.now()
|
|
2722
|
+
isFetching: false
|
|
2767
2723
|
};
|
|
2768
|
-
} finally {
|
|
2769
|
-
// If we showed the pending component, that means
|
|
2770
|
-
// we already moved the pendingMatches to the matches
|
|
2771
|
-
// state, so we need to update that specific match
|
|
2772
|
-
if (didShowPending && pendingMinMs && match.showPending) {
|
|
2773
|
-
updateMatch(match);
|
|
2774
|
-
}
|
|
2775
2724
|
}
|
|
2776
2725
|
updateMatch(match);
|
|
2777
2726
|
};
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2727
|
+
|
|
2728
|
+
// This is where all of the stale-while-revalidate magic happens
|
|
2729
|
+
const age = Date.now() - match.updatedAt;
|
|
2730
|
+
let staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 30_000 // 30 seconds for preloads by default
|
|
2731
|
+
: route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
|
|
2732
|
+
if (match.status === 'success') {
|
|
2733
|
+
// Background Fetching, no need to wait
|
|
2734
|
+
if (age > staleAge) {
|
|
2735
|
+
fetch();
|
|
2736
|
+
}
|
|
2781
2737
|
} else {
|
|
2782
|
-
// Critical Fetching
|
|
2738
|
+
// Critical Fetching, we need to await
|
|
2783
2739
|
|
|
2784
2740
|
// If we need to potentially show the pending component,
|
|
2785
2741
|
// start a timer to show it after the pendingMs
|
|
@@ -2798,9 +2754,6 @@
|
|
|
2798
2754
|
await fetch();
|
|
2799
2755
|
}
|
|
2800
2756
|
resolve();
|
|
2801
|
-
// No Fetching
|
|
2802
|
-
|
|
2803
|
-
resolve();
|
|
2804
2757
|
}));
|
|
2805
2758
|
});
|
|
2806
2759
|
await Promise.all(matchPromises);
|
|
@@ -2827,12 +2780,16 @@
|
|
|
2827
2780
|
let pendingMatches;
|
|
2828
2781
|
const previousMatches = this.state.matches;
|
|
2829
2782
|
this.__store.batch(() => {
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2783
|
+
// This is where all of the garbage collection magic happens
|
|
2784
|
+
this.__store.setState(s => {
|
|
2785
|
+
return {
|
|
2786
|
+
...s,
|
|
2787
|
+
cachedMatches: s.cachedMatches.filter(d => {
|
|
2788
|
+
const route = this.looseRoutesById[d.routeId];
|
|
2789
|
+
return d.status !== 'error' && Date.now() - d.updatedAt < (route.options.gcTime ?? this.options.defaultGcTime ?? 5 * 60 * 1000);
|
|
2790
|
+
})
|
|
2791
|
+
};
|
|
2792
|
+
});
|
|
2836
2793
|
|
|
2837
2794
|
// Match the routes
|
|
2838
2795
|
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
@@ -2840,12 +2797,13 @@
|
|
|
2840
2797
|
});
|
|
2841
2798
|
|
|
2842
2799
|
// Ingest the new matches
|
|
2800
|
+
// If a cached moved to pendingMatches, remove it from cachedMatches
|
|
2843
2801
|
this.__store.setState(s => ({
|
|
2844
2802
|
...s,
|
|
2845
2803
|
isLoading: true,
|
|
2846
2804
|
location: next,
|
|
2847
2805
|
pendingMatches,
|
|
2848
|
-
|
|
2806
|
+
cachedMatches: s.cachedMatches.filter(d => {
|
|
2849
2807
|
return !pendingMatches.find(e => e.id === d.id);
|
|
2850
2808
|
})
|
|
2851
2809
|
}));
|
|
@@ -2867,19 +2825,23 @@
|
|
|
2867
2825
|
if (latestPromise = this.checkLatest(promise)) {
|
|
2868
2826
|
return latestPromise;
|
|
2869
2827
|
}
|
|
2870
|
-
const
|
|
2871
|
-
const
|
|
2872
|
-
const
|
|
2828
|
+
const exitingMatches = previousMatches.filter(match => !pendingMatches.find(d => d.id === match.id));
|
|
2829
|
+
const enteringMatches = pendingMatches.filter(match => !previousMatches.find(d => d.id === match.id));
|
|
2830
|
+
const stayingMatches = previousMatches.filter(match => pendingMatches.find(d => d.id === match.id));
|
|
2831
|
+
|
|
2832
|
+
// Commit the pending matches. If a previous match was
|
|
2833
|
+
// removed, place it in the cachedMatches
|
|
2873
2834
|
this.__store.setState(s => ({
|
|
2874
2835
|
...s,
|
|
2875
2836
|
isLoading: false,
|
|
2876
2837
|
matches: pendingMatches,
|
|
2877
|
-
pendingMatches: undefined
|
|
2838
|
+
pendingMatches: undefined,
|
|
2839
|
+
cachedMatches: [...s.cachedMatches, ...exitingMatches.filter(d => d.status !== 'error')]
|
|
2878
2840
|
}))
|
|
2879
2841
|
|
|
2880
2842
|
//
|
|
2881
2843
|
;
|
|
2882
|
-
[[
|
|
2844
|
+
[[exitingMatches, 'onLeave'], [enteringMatches, 'onEnter'], [stayingMatches, 'onStay']].forEach(([matches, hook]) => {
|
|
2883
2845
|
matches.forEach(match => {
|
|
2884
2846
|
this.looseRoutesById[match.routeId].options[hook]?.(match);
|
|
2885
2847
|
});
|
|
@@ -2907,13 +2869,13 @@
|
|
|
2907
2869
|
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
2908
2870
|
throwOnError: true
|
|
2909
2871
|
});
|
|
2910
|
-
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.
|
|
2872
|
+
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.cachedMatches]?.map(d => [d.id, true]));
|
|
2911
2873
|
this.__store.batch(() => {
|
|
2912
2874
|
matches.forEach(match => {
|
|
2913
2875
|
if (!loadedMatchIds[match.id]) {
|
|
2914
2876
|
this.__store.setState(s => ({
|
|
2915
2877
|
...s,
|
|
2916
|
-
|
|
2878
|
+
cachedMatches: [...s.cachedMatches, match]
|
|
2917
2879
|
}));
|
|
2918
2880
|
}
|
|
2919
2881
|
});
|
|
@@ -3043,7 +3005,7 @@
|
|
|
3043
3005
|
location,
|
|
3044
3006
|
matches: [],
|
|
3045
3007
|
pendingMatches: [],
|
|
3046
|
-
|
|
3008
|
+
cachedMatches: [],
|
|
3047
3009
|
lastUpdated: Date.now()
|
|
3048
3010
|
};
|
|
3049
3011
|
}
|