@tanstack/react-router 0.0.1-beta.273 → 0.0.1-beta.275
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 +9 -6
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/fileRoute.js.map +1 -1
- package/build/cjs/index.js +4 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/redirects.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +163 -105
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +170 -108
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +353 -353
- package/build/types/Matches.d.ts +4 -3
- package/build/types/RouterProvider.d.ts +1 -1
- package/build/types/fileRoute.d.ts +2 -2
- package/build/types/redirects.d.ts +1 -1
- package/build/types/route.d.ts +24 -24
- package/build/types/routeInfo.d.ts +1 -1
- package/build/types/router.d.ts +3 -1
- package/build/umd/index.development.js +172 -111
- 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 +4 -3
- package/src/RouterProvider.tsx +11 -5
- package/src/fileRoute.ts +3 -0
- package/src/redirects.ts +1 -1
- package/src/route.ts +31 -20
- package/src/routeInfo.ts +2 -0
- package/src/router.ts +211 -133
|
@@ -1080,9 +1080,13 @@
|
|
|
1080
1080
|
});
|
|
1081
1081
|
}
|
|
1082
1082
|
|
|
1083
|
-
|
|
1083
|
+
exports.routerContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
1084
1084
|
if (typeof document !== 'undefined') {
|
|
1085
|
-
window.__TSR_ROUTER_CONTEXT__
|
|
1085
|
+
if (window.__TSR_ROUTER_CONTEXT__) {
|
|
1086
|
+
exports.routerContext = window.__TSR_ROUTER_CONTEXT__;
|
|
1087
|
+
} else {
|
|
1088
|
+
window.__TSR_ROUTER_CONTEXT__ = exports.routerContext;
|
|
1089
|
+
}
|
|
1086
1090
|
}
|
|
1087
1091
|
function RouterProvider({
|
|
1088
1092
|
router,
|
|
@@ -1098,7 +1102,7 @@
|
|
|
1098
1102
|
}
|
|
1099
1103
|
});
|
|
1100
1104
|
const matches = router.options.InnerWrap ? /*#__PURE__*/React__namespace.createElement(router.options.InnerWrap, null, /*#__PURE__*/React__namespace.createElement(Matches, null)) : /*#__PURE__*/React__namespace.createElement(Matches, null);
|
|
1101
|
-
const provider = /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
1105
|
+
const provider = /*#__PURE__*/React__namespace.createElement(exports.routerContext.Provider, {
|
|
1102
1106
|
value: router
|
|
1103
1107
|
}, matches, /*#__PURE__*/React__namespace.createElement(Transitioner, null));
|
|
1104
1108
|
if (router.options.Wrap) {
|
|
@@ -1192,14 +1196,14 @@
|
|
|
1192
1196
|
return null;
|
|
1193
1197
|
}
|
|
1194
1198
|
function getRouteMatch(state, id) {
|
|
1195
|
-
return [...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
1199
|
+
return [...state.preloadMatches, ...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
1196
1200
|
}
|
|
1197
1201
|
function useRouterState(opts) {
|
|
1198
1202
|
const router = useRouter();
|
|
1199
1203
|
return useStore(router.__store, opts?.select);
|
|
1200
1204
|
}
|
|
1201
1205
|
function useRouter() {
|
|
1202
|
-
const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || routerContext : routerContext;
|
|
1206
|
+
const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || exports.routerContext : exports.routerContext;
|
|
1203
1207
|
const value = React__namespace.useContext(resolvedContext);
|
|
1204
1208
|
warning(value, 'useRouter must be used inside a <RouterProvider> component!');
|
|
1205
1209
|
return value;
|
|
@@ -2261,11 +2265,18 @@
|
|
|
2261
2265
|
return [parentSearch, searchError];
|
|
2262
2266
|
}
|
|
2263
2267
|
})();
|
|
2268
|
+
|
|
2269
|
+
// This is where we need to call route.options.loaderDeps() to get any additional
|
|
2270
|
+
// deps that the route's loader function might need to run. We need to do this
|
|
2271
|
+
// before we create the match so that we can pass the deps to the route's
|
|
2272
|
+
// potential key function which is used to uniquely identify the route match in state
|
|
2273
|
+
|
|
2274
|
+
const loaderDeps = route.options.loaderDeps?.({
|
|
2275
|
+
search: preMatchSearch
|
|
2276
|
+
}) ?? '';
|
|
2277
|
+
const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : '';
|
|
2264
2278
|
const interpolatedPath = interpolatePath(route.fullPath, routeParams);
|
|
2265
|
-
const matchId = interpolatePath(route.id, routeParams, true) +
|
|
2266
|
-
search: preMatchSearch,
|
|
2267
|
-
location: this.state.location
|
|
2268
|
-
}) ?? '');
|
|
2279
|
+
const matchId = interpolatePath(route.id, routeParams, true) + loaderDepsHash;
|
|
2269
2280
|
|
|
2270
2281
|
// Waste not, want not. If we already have a match for this route,
|
|
2271
2282
|
// reuse it. This is important for layout routes, which might stick
|
|
@@ -2296,8 +2307,9 @@
|
|
|
2296
2307
|
context: undefined,
|
|
2297
2308
|
abortController: new AbortController(),
|
|
2298
2309
|
shouldReloadDeps: undefined,
|
|
2299
|
-
|
|
2300
|
-
cause
|
|
2310
|
+
fetchCount: 0,
|
|
2311
|
+
cause,
|
|
2312
|
+
loaderDeps
|
|
2301
2313
|
};
|
|
2302
2314
|
|
|
2303
2315
|
// Regardless of whether we're reusing an existing match or creating
|
|
@@ -2505,10 +2517,13 @@
|
|
|
2505
2517
|
}) => {
|
|
2506
2518
|
let latestPromise;
|
|
2507
2519
|
let firstBadMatchIndex;
|
|
2508
|
-
const
|
|
2520
|
+
const updateMatch = match => {
|
|
2521
|
+
const isPreload = this.state.preloadMatches.find(d => d.id === match.id);
|
|
2522
|
+
const isPending = this.state.pendingMatches?.find(d => d.id === match.id);
|
|
2523
|
+
const matchesKey = isPreload ? 'preloadMatches' : isPending ? 'pendingMatches' : 'matches';
|
|
2509
2524
|
this.__store.setState(s => ({
|
|
2510
2525
|
...s,
|
|
2511
|
-
|
|
2526
|
+
[matchesKey]: s[matchesKey]?.map(d => d.id === match.id ? match : d)
|
|
2512
2527
|
}));
|
|
2513
2528
|
};
|
|
2514
2529
|
|
|
@@ -2561,7 +2576,7 @@
|
|
|
2561
2576
|
from: match.pathname
|
|
2562
2577
|
}),
|
|
2563
2578
|
buildLocation: this.buildLocation,
|
|
2564
|
-
cause: match.cause
|
|
2579
|
+
cause: preload ? 'preload' : match.cause
|
|
2565
2580
|
})) ?? {};
|
|
2566
2581
|
if (isRedirect(beforeLoadContext)) {
|
|
2567
2582
|
throw beforeLoadContext;
|
|
@@ -2591,7 +2606,7 @@
|
|
|
2591
2606
|
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
2592
2607
|
const matchPromises = [];
|
|
2593
2608
|
validResolvedMatches.forEach((match, index) => {
|
|
2594
|
-
matchPromises.push((async
|
|
2609
|
+
matchPromises.push(new Promise(async resolve => {
|
|
2595
2610
|
const parentMatchPromise = matchPromises[index - 1];
|
|
2596
2611
|
const route = this.looseRoutesById[match.routeId];
|
|
2597
2612
|
const handleErrorAndRedirect = err => {
|
|
@@ -2606,92 +2621,95 @@
|
|
|
2606
2621
|
let loadPromise;
|
|
2607
2622
|
matches[index] = match = {
|
|
2608
2623
|
...match,
|
|
2609
|
-
fetchedAt: Date.now(),
|
|
2610
2624
|
showPending: false
|
|
2611
2625
|
};
|
|
2626
|
+
let didShowPending = false;
|
|
2612
2627
|
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
};
|
|
2628
|
+
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2629
|
+
const shouldPending = !preload && pendingMs && (route.options.pendingComponent ?? this.options.defaultPendingComponent);
|
|
2630
|
+
const fetch = async () => {
|
|
2631
|
+
if (match.isFetching) {
|
|
2632
|
+
loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
|
|
2633
|
+
} else {
|
|
2634
|
+
const loaderContext = {
|
|
2635
|
+
params: match.params,
|
|
2636
|
+
deps: match.loaderDeps,
|
|
2637
|
+
preload: !!preload,
|
|
2638
|
+
parentMatchPromise,
|
|
2639
|
+
abortController: match.abortController,
|
|
2640
|
+
context: match.context,
|
|
2641
|
+
location: this.state.location,
|
|
2642
|
+
navigate: opts => this.navigate({
|
|
2643
|
+
...opts,
|
|
2644
|
+
from: match.pathname
|
|
2645
|
+
}),
|
|
2646
|
+
cause: preload ? 'preload' : match.cause
|
|
2647
|
+
};
|
|
2634
2648
|
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2649
|
+
// Default to reloading the route all the time
|
|
2650
|
+
let shouldLoad = true;
|
|
2651
|
+
const shouldReloadFn = route.options.shouldReload;
|
|
2652
|
+
let shouldReloadDeps = typeof shouldReloadFn === 'function' ? shouldReloadFn(loaderContext) : !!(shouldReloadFn ?? true);
|
|
2653
|
+
const compareDeps = () => {
|
|
2654
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
2655
|
+
// compare the deps to see if they've changed
|
|
2656
|
+
shouldLoad = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
|
|
2657
|
+
} else {
|
|
2658
|
+
shouldLoad = !!shouldReloadDeps;
|
|
2659
|
+
}
|
|
2660
|
+
};
|
|
2661
|
+
|
|
2662
|
+
// If it's the first preload, or the route is entering, or we're
|
|
2663
|
+
// invalidating, we definitely need to load the route
|
|
2664
|
+
if (invalidate) ; else if (preload) {
|
|
2665
|
+
if (!match.fetchCount) ; else {
|
|
2666
|
+
compareDeps();
|
|
2667
|
+
}
|
|
2668
|
+
} else if (match.cause === 'enter') {
|
|
2669
|
+
if (!match.fetchCount) ; else {
|
|
2670
|
+
compareDeps();
|
|
2671
|
+
}
|
|
2645
2672
|
} else {
|
|
2646
|
-
|
|
2673
|
+
compareDeps();
|
|
2674
|
+
}
|
|
2675
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
2676
|
+
matches[index] = match = {
|
|
2677
|
+
...match,
|
|
2678
|
+
shouldReloadDeps
|
|
2679
|
+
};
|
|
2647
2680
|
}
|
|
2648
|
-
}
|
|
2649
2681
|
|
|
2650
|
-
|
|
2651
|
-
|
|
2682
|
+
// If the user doesn't want the route to reload, just
|
|
2683
|
+
// resolve with the existing loader data
|
|
2652
2684
|
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
...match,
|
|
2659
|
-
isFetching: true
|
|
2660
|
-
};
|
|
2661
|
-
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2662
|
-
const component = route.options[type];
|
|
2663
|
-
if (component?.preload) {
|
|
2664
|
-
await component.preload();
|
|
2685
|
+
if (!shouldLoad) {
|
|
2686
|
+
loadPromise = Promise.resolve(match.loaderData);
|
|
2687
|
+
} else {
|
|
2688
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2689
|
+
resolve();
|
|
2665
2690
|
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
matches[index] = match = {
|
|
2672
|
-
...match,
|
|
2673
|
-
loadPromise
|
|
2674
|
-
};
|
|
2675
|
-
if (!preload) {
|
|
2676
|
-
updatePendingMatch(match);
|
|
2677
|
-
}
|
|
2678
|
-
let didShowPending = false;
|
|
2679
|
-
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2680
|
-
await new Promise(async resolve => {
|
|
2681
|
-
// If the route has a pending component and a pendingMs option,
|
|
2682
|
-
// forcefully show the pending component
|
|
2683
|
-
if (pendingPromise) {
|
|
2684
|
-
pendingPromise.then(() => {
|
|
2685
|
-
if (latestPromise = checkLatest()) return;
|
|
2686
|
-
didShowPending = true;
|
|
2691
|
+
|
|
2692
|
+
// Otherwise, load the route
|
|
2687
2693
|
matches[index] = match = {
|
|
2688
2694
|
...match,
|
|
2689
|
-
|
|
2695
|
+
isFetching: true,
|
|
2696
|
+
fetchCount: match.fetchCount + 1
|
|
2690
2697
|
};
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2698
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2699
|
+
const component = route.options[type];
|
|
2700
|
+
if (component?.preload) {
|
|
2701
|
+
await component.preload();
|
|
2702
|
+
}
|
|
2703
|
+
}));
|
|
2704
|
+
const loaderPromise = route.options.loader?.(loaderContext);
|
|
2705
|
+
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2706
|
+
}
|
|
2694
2707
|
}
|
|
2708
|
+
matches[index] = match = {
|
|
2709
|
+
...match,
|
|
2710
|
+
loadPromise
|
|
2711
|
+
};
|
|
2712
|
+
updateMatch(match);
|
|
2695
2713
|
try {
|
|
2696
2714
|
const loaderData = await loadPromise;
|
|
2697
2715
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
@@ -2732,18 +2750,38 @@
|
|
|
2732
2750
|
// we already moved the pendingMatches to the matches
|
|
2733
2751
|
// state, so we need to update that specific match
|
|
2734
2752
|
if (didShowPending && pendingMinMs && match.showPending) {
|
|
2735
|
-
|
|
2736
|
-
...s,
|
|
2737
|
-
matches: s.matches?.map(d => d.id === match.id ? match : d)
|
|
2738
|
-
}));
|
|
2753
|
+
updateMatch(match);
|
|
2739
2754
|
}
|
|
2740
2755
|
}
|
|
2741
|
-
|
|
2742
|
-
|
|
2756
|
+
updateMatch(match);
|
|
2757
|
+
};
|
|
2758
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2759
|
+
// Background Fetching
|
|
2760
|
+
fetch();
|
|
2761
|
+
} else {
|
|
2762
|
+
// Critical Fetching
|
|
2763
|
+
|
|
2764
|
+
// If we need to potentially show the pending component,
|
|
2765
|
+
// start a timer to show it after the pendingMs
|
|
2766
|
+
if (shouldPending) {
|
|
2767
|
+
new Promise(r => setTimeout(r, pendingMs)).then(async () => {
|
|
2768
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
2769
|
+
didShowPending = true;
|
|
2770
|
+
matches[index] = match = {
|
|
2771
|
+
...match,
|
|
2772
|
+
showPending: true
|
|
2773
|
+
};
|
|
2774
|
+
updateMatch(match);
|
|
2775
|
+
resolve();
|
|
2776
|
+
});
|
|
2743
2777
|
}
|
|
2744
|
-
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2778
|
+
await fetch();
|
|
2779
|
+
}
|
|
2780
|
+
resolve();
|
|
2781
|
+
// No Fetching
|
|
2782
|
+
|
|
2783
|
+
resolve();
|
|
2784
|
+
}));
|
|
2747
2785
|
});
|
|
2748
2786
|
await Promise.all(matchPromises);
|
|
2749
2787
|
return matches;
|
|
@@ -2766,20 +2804,32 @@
|
|
|
2766
2804
|
toLocation: next,
|
|
2767
2805
|
pathChanged: pathDidChange
|
|
2768
2806
|
});
|
|
2769
|
-
|
|
2770
|
-
// Match the routes
|
|
2771
|
-
let pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2772
|
-
debug: true
|
|
2773
|
-
});
|
|
2807
|
+
let pendingMatches;
|
|
2774
2808
|
const previousMatches = this.state.matches;
|
|
2809
|
+
this.__store.batch(() => {
|
|
2810
|
+
this.__store.setState(s => ({
|
|
2811
|
+
...s,
|
|
2812
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
2813
|
+
return Date.now() - d.updatedAt < (this.options.defaultPreloadMaxAge ?? 3000);
|
|
2814
|
+
})
|
|
2815
|
+
}));
|
|
2775
2816
|
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2817
|
+
// Match the routes
|
|
2818
|
+
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2819
|
+
debug: true
|
|
2820
|
+
});
|
|
2821
|
+
|
|
2822
|
+
// Ingest the new matches
|
|
2823
|
+
this.__store.setState(s => ({
|
|
2824
|
+
...s,
|
|
2825
|
+
isLoading: true,
|
|
2826
|
+
location: next,
|
|
2827
|
+
pendingMatches,
|
|
2828
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
2829
|
+
return !pendingMatches.find(e => e.id === d.id);
|
|
2830
|
+
})
|
|
2831
|
+
}));
|
|
2832
|
+
});
|
|
2783
2833
|
try {
|
|
2784
2834
|
try {
|
|
2785
2835
|
// Load the matches
|
|
@@ -2837,6 +2887,17 @@
|
|
|
2837
2887
|
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
2838
2888
|
throwOnError: true
|
|
2839
2889
|
});
|
|
2890
|
+
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.preloadMatches]?.map(d => [d.id, true]));
|
|
2891
|
+
this.__store.batch(() => {
|
|
2892
|
+
matches.forEach(match => {
|
|
2893
|
+
if (!loadedMatchIds[match.id]) {
|
|
2894
|
+
this.__store.setState(s => ({
|
|
2895
|
+
...s,
|
|
2896
|
+
preloadMatches: [...s.preloadMatches, match]
|
|
2897
|
+
}));
|
|
2898
|
+
}
|
|
2899
|
+
});
|
|
2900
|
+
});
|
|
2840
2901
|
matches = await this.loadMatches({
|
|
2841
2902
|
matches,
|
|
2842
2903
|
preload: true,
|
|
@@ -2899,7 +2960,7 @@
|
|
|
2899
2960
|
dehydrate = () => {
|
|
2900
2961
|
return {
|
|
2901
2962
|
state: {
|
|
2902
|
-
dehydratedMatches: this.state.matches.map(d => pick(d, ['
|
|
2963
|
+
dehydratedMatches: this.state.matches.map(d => pick(d, ['id', 'status', 'updatedAt', 'loaderData']))
|
|
2903
2964
|
}
|
|
2904
2965
|
};
|
|
2905
2966
|
};
|
|
@@ -2962,6 +3023,7 @@
|
|
|
2962
3023
|
location,
|
|
2963
3024
|
matches: [],
|
|
2964
3025
|
pendingMatches: [],
|
|
3026
|
+
preloadMatches: [],
|
|
2965
3027
|
lastUpdated: Date.now()
|
|
2966
3028
|
};
|
|
2967
3029
|
}
|
|
@@ -3255,7 +3317,6 @@
|
|
|
3255
3317
|
exports.resolvePath = resolvePath;
|
|
3256
3318
|
exports.rootRouteId = rootRouteId;
|
|
3257
3319
|
exports.rootRouteWithContext = rootRouteWithContext;
|
|
3258
|
-
exports.routerContext = routerContext;
|
|
3259
3320
|
exports.shallow = shallow;
|
|
3260
3321
|
exports.stringifySearchWith = stringifySearchWith;
|
|
3261
3322
|
exports.trimPath = trimPath;
|