@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
package/build/cjs/router.js
CHANGED
|
@@ -318,11 +318,18 @@ class Router {
|
|
|
318
318
|
return [parentSearch, searchError];
|
|
319
319
|
}
|
|
320
320
|
})();
|
|
321
|
+
|
|
322
|
+
// This is where we need to call route.options.loaderDeps() to get any additional
|
|
323
|
+
// deps that the route's loader function might need to run. We need to do this
|
|
324
|
+
// before we create the match so that we can pass the deps to the route's
|
|
325
|
+
// potential key function which is used to uniquely identify the route match in state
|
|
326
|
+
|
|
327
|
+
const loaderDeps = route.options.loaderDeps?.({
|
|
328
|
+
search: preMatchSearch
|
|
329
|
+
}) ?? '';
|
|
330
|
+
const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : '';
|
|
321
331
|
const interpolatedPath = path.interpolatePath(route.fullPath, routeParams);
|
|
322
|
-
const matchId = path.interpolatePath(route.id, routeParams, true) +
|
|
323
|
-
search: preMatchSearch,
|
|
324
|
-
location: this.state.location
|
|
325
|
-
}) ?? '');
|
|
332
|
+
const matchId = path.interpolatePath(route.id, routeParams, true) + loaderDepsHash;
|
|
326
333
|
|
|
327
334
|
// Waste not, want not. If we already have a match for this route,
|
|
328
335
|
// reuse it. This is important for layout routes, which might stick
|
|
@@ -353,8 +360,9 @@ class Router {
|
|
|
353
360
|
context: undefined,
|
|
354
361
|
abortController: new AbortController(),
|
|
355
362
|
shouldReloadDeps: undefined,
|
|
356
|
-
|
|
357
|
-
cause
|
|
363
|
+
fetchCount: 0,
|
|
364
|
+
cause,
|
|
365
|
+
loaderDeps
|
|
358
366
|
};
|
|
359
367
|
|
|
360
368
|
// Regardless of whether we're reusing an existing match or creating
|
|
@@ -562,10 +570,13 @@ class Router {
|
|
|
562
570
|
}) => {
|
|
563
571
|
let latestPromise;
|
|
564
572
|
let firstBadMatchIndex;
|
|
565
|
-
const
|
|
573
|
+
const updateMatch = match => {
|
|
574
|
+
const isPreload = this.state.preloadMatches.find(d => d.id === match.id);
|
|
575
|
+
const isPending = this.state.pendingMatches?.find(d => d.id === match.id);
|
|
576
|
+
const matchesKey = isPreload ? 'preloadMatches' : isPending ? 'pendingMatches' : 'matches';
|
|
566
577
|
this.__store.setState(s => ({
|
|
567
578
|
...s,
|
|
568
|
-
|
|
579
|
+
[matchesKey]: s[matchesKey]?.map(d => d.id === match.id ? match : d)
|
|
569
580
|
}));
|
|
570
581
|
};
|
|
571
582
|
|
|
@@ -618,7 +629,7 @@ class Router {
|
|
|
618
629
|
from: match.pathname
|
|
619
630
|
}),
|
|
620
631
|
buildLocation: this.buildLocation,
|
|
621
|
-
cause: match.cause
|
|
632
|
+
cause: preload ? 'preload' : match.cause
|
|
622
633
|
})) ?? {};
|
|
623
634
|
if (redirects.isRedirect(beforeLoadContext)) {
|
|
624
635
|
throw beforeLoadContext;
|
|
@@ -648,7 +659,7 @@ class Router {
|
|
|
648
659
|
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
649
660
|
const matchPromises = [];
|
|
650
661
|
validResolvedMatches.forEach((match, index) => {
|
|
651
|
-
matchPromises.push((async
|
|
662
|
+
matchPromises.push(new Promise(async resolve => {
|
|
652
663
|
const parentMatchPromise = matchPromises[index - 1];
|
|
653
664
|
const route = this.looseRoutesById[match.routeId];
|
|
654
665
|
const handleErrorAndRedirect = err => {
|
|
@@ -663,92 +674,95 @@ class Router {
|
|
|
663
674
|
let loadPromise;
|
|
664
675
|
matches[index] = match = {
|
|
665
676
|
...match,
|
|
666
|
-
fetchedAt: Date.now(),
|
|
667
677
|
showPending: false
|
|
668
678
|
};
|
|
679
|
+
let didShowPending = false;
|
|
669
680
|
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
};
|
|
681
|
+
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
682
|
+
const shouldPending = !preload && pendingMs && (route.options.pendingComponent ?? this.options.defaultPendingComponent);
|
|
683
|
+
const fetch = async () => {
|
|
684
|
+
if (match.isFetching) {
|
|
685
|
+
loadPromise = RouterProvider.getRouteMatch(this.state, match.id)?.loadPromise;
|
|
686
|
+
} else {
|
|
687
|
+
const loaderContext = {
|
|
688
|
+
params: match.params,
|
|
689
|
+
deps: match.loaderDeps,
|
|
690
|
+
preload: !!preload,
|
|
691
|
+
parentMatchPromise,
|
|
692
|
+
abortController: match.abortController,
|
|
693
|
+
context: match.context,
|
|
694
|
+
location: this.state.location,
|
|
695
|
+
navigate: opts => this.navigate({
|
|
696
|
+
...opts,
|
|
697
|
+
from: match.pathname
|
|
698
|
+
}),
|
|
699
|
+
cause: preload ? 'preload' : match.cause
|
|
700
|
+
};
|
|
691
701
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
+
// Default to reloading the route all the time
|
|
703
|
+
let shouldLoad = true;
|
|
704
|
+
const shouldReloadFn = route.options.shouldReload;
|
|
705
|
+
let shouldReloadDeps = typeof shouldReloadFn === 'function' ? shouldReloadFn(loaderContext) : !!(shouldReloadFn ?? true);
|
|
706
|
+
const compareDeps = () => {
|
|
707
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
708
|
+
// compare the deps to see if they've changed
|
|
709
|
+
shouldLoad = !utils.deepEqual(shouldReloadDeps, match.shouldReloadDeps);
|
|
710
|
+
} else {
|
|
711
|
+
shouldLoad = !!shouldReloadDeps;
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// If it's the first preload, or the route is entering, or we're
|
|
716
|
+
// invalidating, we definitely need to load the route
|
|
717
|
+
if (invalidate) ; else if (preload) {
|
|
718
|
+
if (!match.fetchCount) ; else {
|
|
719
|
+
compareDeps();
|
|
720
|
+
}
|
|
721
|
+
} else if (match.cause === 'enter') {
|
|
722
|
+
if (!match.fetchCount) ; else {
|
|
723
|
+
compareDeps();
|
|
724
|
+
}
|
|
702
725
|
} else {
|
|
703
|
-
|
|
726
|
+
compareDeps();
|
|
727
|
+
}
|
|
728
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
729
|
+
matches[index] = match = {
|
|
730
|
+
...match,
|
|
731
|
+
shouldReloadDeps
|
|
732
|
+
};
|
|
704
733
|
}
|
|
705
|
-
}
|
|
706
734
|
|
|
707
|
-
|
|
708
|
-
|
|
735
|
+
// If the user doesn't want the route to reload, just
|
|
736
|
+
// resolve with the existing loader data
|
|
709
737
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
...match,
|
|
716
|
-
isFetching: true
|
|
717
|
-
};
|
|
718
|
-
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
719
|
-
const component = route.options[type];
|
|
720
|
-
if (component?.preload) {
|
|
721
|
-
await component.preload();
|
|
738
|
+
if (!shouldLoad) {
|
|
739
|
+
loadPromise = Promise.resolve(match.loaderData);
|
|
740
|
+
} else {
|
|
741
|
+
if (match.fetchCount && match.status === 'success') {
|
|
742
|
+
resolve();
|
|
722
743
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
matches[index] = match = {
|
|
729
|
-
...match,
|
|
730
|
-
loadPromise
|
|
731
|
-
};
|
|
732
|
-
if (!preload) {
|
|
733
|
-
updatePendingMatch(match);
|
|
734
|
-
}
|
|
735
|
-
let didShowPending = false;
|
|
736
|
-
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
737
|
-
await new Promise(async resolve => {
|
|
738
|
-
// If the route has a pending component and a pendingMs option,
|
|
739
|
-
// forcefully show the pending component
|
|
740
|
-
if (pendingPromise) {
|
|
741
|
-
pendingPromise.then(() => {
|
|
742
|
-
if (latestPromise = checkLatest()) return;
|
|
743
|
-
didShowPending = true;
|
|
744
|
+
|
|
745
|
+
// Otherwise, load the route
|
|
744
746
|
matches[index] = match = {
|
|
745
747
|
...match,
|
|
746
|
-
|
|
748
|
+
isFetching: true,
|
|
749
|
+
fetchCount: match.fetchCount + 1
|
|
747
750
|
};
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
752
|
+
const component = route.options[type];
|
|
753
|
+
if (component?.preload) {
|
|
754
|
+
await component.preload();
|
|
755
|
+
}
|
|
756
|
+
}));
|
|
757
|
+
const loaderPromise = route.options.loader?.(loaderContext);
|
|
758
|
+
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
759
|
+
}
|
|
751
760
|
}
|
|
761
|
+
matches[index] = match = {
|
|
762
|
+
...match,
|
|
763
|
+
loadPromise
|
|
764
|
+
};
|
|
765
|
+
updateMatch(match);
|
|
752
766
|
try {
|
|
753
767
|
const loaderData = await loadPromise;
|
|
754
768
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
@@ -789,18 +803,38 @@ class Router {
|
|
|
789
803
|
// we already moved the pendingMatches to the matches
|
|
790
804
|
// state, so we need to update that specific match
|
|
791
805
|
if (didShowPending && pendingMinMs && match.showPending) {
|
|
792
|
-
|
|
793
|
-
...s,
|
|
794
|
-
matches: s.matches?.map(d => d.id === match.id ? match : d)
|
|
795
|
-
}));
|
|
806
|
+
updateMatch(match);
|
|
796
807
|
}
|
|
797
808
|
}
|
|
798
|
-
|
|
799
|
-
|
|
809
|
+
updateMatch(match);
|
|
810
|
+
};
|
|
811
|
+
if (match.fetchCount && match.status === 'success') {
|
|
812
|
+
// Background Fetching
|
|
813
|
+
fetch();
|
|
814
|
+
} else {
|
|
815
|
+
// Critical Fetching
|
|
816
|
+
|
|
817
|
+
// If we need to potentially show the pending component,
|
|
818
|
+
// start a timer to show it after the pendingMs
|
|
819
|
+
if (shouldPending) {
|
|
820
|
+
new Promise(r => setTimeout(r, pendingMs)).then(async () => {
|
|
821
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
822
|
+
didShowPending = true;
|
|
823
|
+
matches[index] = match = {
|
|
824
|
+
...match,
|
|
825
|
+
showPending: true
|
|
826
|
+
};
|
|
827
|
+
updateMatch(match);
|
|
828
|
+
resolve();
|
|
829
|
+
});
|
|
800
830
|
}
|
|
801
|
-
|
|
802
|
-
}
|
|
803
|
-
|
|
831
|
+
await fetch();
|
|
832
|
+
}
|
|
833
|
+
resolve();
|
|
834
|
+
// No Fetching
|
|
835
|
+
|
|
836
|
+
resolve();
|
|
837
|
+
}));
|
|
804
838
|
});
|
|
805
839
|
await Promise.all(matchPromises);
|
|
806
840
|
return matches;
|
|
@@ -823,20 +857,32 @@ class Router {
|
|
|
823
857
|
toLocation: next,
|
|
824
858
|
pathChanged: pathDidChange
|
|
825
859
|
});
|
|
826
|
-
|
|
827
|
-
// Match the routes
|
|
828
|
-
let pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
829
|
-
debug: true
|
|
830
|
-
});
|
|
860
|
+
let pendingMatches;
|
|
831
861
|
const previousMatches = this.state.matches;
|
|
862
|
+
this.__store.batch(() => {
|
|
863
|
+
this.__store.setState(s => ({
|
|
864
|
+
...s,
|
|
865
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
866
|
+
return Date.now() - d.updatedAt < (this.options.defaultPreloadMaxAge ?? 3000);
|
|
867
|
+
})
|
|
868
|
+
}));
|
|
832
869
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
870
|
+
// Match the routes
|
|
871
|
+
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
872
|
+
debug: true
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
// Ingest the new matches
|
|
876
|
+
this.__store.setState(s => ({
|
|
877
|
+
...s,
|
|
878
|
+
isLoading: true,
|
|
879
|
+
location: next,
|
|
880
|
+
pendingMatches,
|
|
881
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
882
|
+
return !pendingMatches.find(e => e.id === d.id);
|
|
883
|
+
})
|
|
884
|
+
}));
|
|
885
|
+
});
|
|
840
886
|
try {
|
|
841
887
|
try {
|
|
842
888
|
// Load the matches
|
|
@@ -894,6 +940,17 @@ class Router {
|
|
|
894
940
|
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
895
941
|
throwOnError: true
|
|
896
942
|
});
|
|
943
|
+
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.preloadMatches]?.map(d => [d.id, true]));
|
|
944
|
+
this.__store.batch(() => {
|
|
945
|
+
matches.forEach(match => {
|
|
946
|
+
if (!loadedMatchIds[match.id]) {
|
|
947
|
+
this.__store.setState(s => ({
|
|
948
|
+
...s,
|
|
949
|
+
preloadMatches: [...s.preloadMatches, match]
|
|
950
|
+
}));
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
});
|
|
897
954
|
matches = await this.loadMatches({
|
|
898
955
|
matches,
|
|
899
956
|
preload: true,
|
|
@@ -956,7 +1013,7 @@ class Router {
|
|
|
956
1013
|
dehydrate = () => {
|
|
957
1014
|
return {
|
|
958
1015
|
state: {
|
|
959
|
-
dehydratedMatches: this.state.matches.map(d => utils.pick(d, ['
|
|
1016
|
+
dehydratedMatches: this.state.matches.map(d => utils.pick(d, ['id', 'status', 'updatedAt', 'loaderData']))
|
|
960
1017
|
}
|
|
961
1018
|
};
|
|
962
1019
|
};
|
|
@@ -1019,6 +1076,7 @@ function getInitialRouterState(location) {
|
|
|
1019
1076
|
location,
|
|
1020
1077
|
matches: [],
|
|
1021
1078
|
pendingMatches: [],
|
|
1079
|
+
preloadMatches: [],
|
|
1022
1080
|
lastUpdated: Date.now()
|
|
1023
1081
|
};
|
|
1024
1082
|
}
|