@tanstack/router-core 1.132.0-alpha.1 → 1.132.0-alpha.2
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/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +7 -9
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +0 -4
- package/dist/cjs/router.cjs +629 -528
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +19 -8
- package/dist/cjs/scroll-restoration.d.cts +0 -9
- package/dist/cjs/ssr/ssr-client.cjs +38 -39
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/typePrimitives.d.cts +6 -6
- package/dist/cjs/utils.cjs +6 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +1 -0
- package/dist/esm/Matches.d.ts +7 -9
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/route.d.ts +0 -4
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +19 -8
- package/dist/esm/router.js +630 -529
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +0 -9
- package/dist/esm/ssr/ssr-client.js +38 -39
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/typePrimitives.d.ts +6 -6
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js +6 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/Matches.ts +16 -8
- package/src/route.ts +10 -2
- package/src/router.ts +909 -717
- package/src/ssr/ssr-client.ts +42 -41
- package/src/typePrimitives.ts +6 -6
- package/src/utils.ts +10 -0
package/dist/cjs/router.cjs
CHANGED
|
@@ -212,13 +212,8 @@ class RouterCore {
|
|
|
212
212
|
const match = this.getMatch(id);
|
|
213
213
|
if (!match) return;
|
|
214
214
|
match.abortController.abort();
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
...prev,
|
|
219
|
-
pendingTimeout: void 0
|
|
220
|
-
};
|
|
221
|
-
});
|
|
215
|
+
clearTimeout(match._nonReactive.pendingTimeout);
|
|
216
|
+
match._nonReactive.pendingTimeout = void 0;
|
|
222
217
|
};
|
|
223
218
|
this.cancelMatches = () => {
|
|
224
219
|
this.state.pendingMatches?.forEach((match) => {
|
|
@@ -232,7 +227,7 @@ class RouterCore {
|
|
|
232
227
|
_buildLocation: true
|
|
233
228
|
});
|
|
234
229
|
const lastMatch = utils.last(allCurrentLocationMatches);
|
|
235
|
-
let fromPath = lastMatch.fullPath;
|
|
230
|
+
let fromPath = this.resolvePathWithBase(lastMatch.fullPath, ".");
|
|
236
231
|
const toPath = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
237
232
|
const routeIsChanging = !!dest.to && !comparePaths(dest.to.toString(), fromPath) && !comparePaths(toPath, fromPath);
|
|
238
233
|
if (dest.unsafeRelative === "path") {
|
|
@@ -255,6 +250,7 @@ class RouterCore {
|
|
|
255
250
|
}
|
|
256
251
|
}
|
|
257
252
|
}
|
|
253
|
+
fromPath = this.resolvePathWithBase(fromPath, ".");
|
|
258
254
|
const fromSearch = lastMatch.search;
|
|
259
255
|
const fromParams = { ...lastMatch.params };
|
|
260
256
|
const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
@@ -267,13 +263,9 @@ class RouterCore {
|
|
|
267
263
|
params: nextParams ?? {},
|
|
268
264
|
parseCache: this.parsePathnameCache
|
|
269
265
|
}).interpolatedPath;
|
|
270
|
-
const destRoutes = this.matchRoutes(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
{
|
|
274
|
-
_buildLocation: true
|
|
275
|
-
}
|
|
276
|
-
).map((d) => this.looseRoutesById[d.routeId]);
|
|
266
|
+
const destRoutes = this.matchRoutes(interpolatedNextTo, void 0, {
|
|
267
|
+
_buildLocation: true
|
|
268
|
+
}).map((d) => this.looseRoutesById[d.routeId]);
|
|
277
269
|
if (Object.keys(nextParams).length > 0) {
|
|
278
270
|
destRoutes.map((route) => {
|
|
279
271
|
return route.options.params?.stringify ?? route.options.stringifyParams;
|
|
@@ -695,502 +687,597 @@ class RouterCore {
|
|
|
695
687
|
const findFn = (d) => d.id === matchId;
|
|
696
688
|
return this.state.cachedMatches.find(findFn) ?? this.state.pendingMatches?.find(findFn) ?? this.state.matches.find(findFn);
|
|
697
689
|
};
|
|
698
|
-
this.
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
690
|
+
this.triggerOnReady = (innerLoadContext) => {
|
|
691
|
+
if (!innerLoadContext.rendered) {
|
|
692
|
+
innerLoadContext.rendered = true;
|
|
693
|
+
return innerLoadContext.onReady?.();
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
this.resolvePreload = (innerLoadContext, matchId) => {
|
|
697
|
+
return !!(innerLoadContext.preload && !this.state.matches.some((d) => d.id === matchId));
|
|
698
|
+
};
|
|
699
|
+
this.handleRedirectAndNotFound = (innerLoadContext, match, err) => {
|
|
700
|
+
if (!redirect.isRedirect(err) && !notFound.isNotFound(err)) return;
|
|
701
|
+
if (redirect.isRedirect(err) && err.redirectHandled && !err.options.reloadDocument) {
|
|
702
|
+
throw err;
|
|
703
|
+
}
|
|
704
|
+
if (match) {
|
|
705
|
+
match._nonReactive.beforeLoadPromise?.resolve();
|
|
706
|
+
match._nonReactive.loaderPromise?.resolve();
|
|
707
|
+
match._nonReactive.beforeLoadPromise = void 0;
|
|
708
|
+
match._nonReactive.loaderPromise = void 0;
|
|
709
|
+
const status = redirect.isRedirect(err) ? "redirected" : "notFound";
|
|
710
|
+
innerLoadContext.updateMatch(match.id, (prev) => ({
|
|
711
|
+
...prev,
|
|
712
|
+
status,
|
|
713
|
+
isFetching: false,
|
|
714
|
+
error: err
|
|
715
|
+
}));
|
|
716
|
+
if (notFound.isNotFound(err) && !err.routeId) {
|
|
717
|
+
err.routeId = match.routeId;
|
|
718
|
+
}
|
|
719
|
+
match._nonReactive.loadPromise?.resolve();
|
|
720
|
+
}
|
|
721
|
+
if (redirect.isRedirect(err)) {
|
|
722
|
+
innerLoadContext.rendered = true;
|
|
723
|
+
err.options._fromLocation = innerLoadContext.location;
|
|
724
|
+
err.redirectHandled = true;
|
|
725
|
+
err = this.resolveRedirect(err);
|
|
726
|
+
throw err;
|
|
727
|
+
} else {
|
|
728
|
+
this._handleNotFound(innerLoadContext, err);
|
|
729
|
+
throw err;
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
this.shouldSkipLoader = (matchId) => {
|
|
733
|
+
const match = this.getMatch(matchId);
|
|
734
|
+
if (!this.isServer && match._nonReactive.dehydrated) {
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
if (this.isServer) {
|
|
738
|
+
if (match.ssr === false) {
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return false;
|
|
743
|
+
};
|
|
744
|
+
this.handleSerialError = (innerLoadContext, index, err, routerCode) => {
|
|
745
|
+
const { id: matchId, routeId } = innerLoadContext.matches[index];
|
|
746
|
+
const route = this.looseRoutesById[routeId];
|
|
747
|
+
if (err instanceof Promise) {
|
|
748
|
+
throw err;
|
|
749
|
+
}
|
|
750
|
+
err.routerCode = routerCode;
|
|
751
|
+
innerLoadContext.firstBadMatchIndex ??= index;
|
|
752
|
+
this.handleRedirectAndNotFound(
|
|
753
|
+
innerLoadContext,
|
|
754
|
+
this.getMatch(matchId),
|
|
755
|
+
err
|
|
756
|
+
);
|
|
757
|
+
try {
|
|
758
|
+
route.options.onError?.(err);
|
|
759
|
+
} catch (errorHandlerErr) {
|
|
760
|
+
err = errorHandlerErr;
|
|
761
|
+
this.handleRedirectAndNotFound(
|
|
762
|
+
innerLoadContext,
|
|
763
|
+
this.getMatch(matchId),
|
|
764
|
+
err
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
innerLoadContext.updateMatch(matchId, (prev) => {
|
|
768
|
+
prev._nonReactive.beforeLoadPromise?.resolve();
|
|
769
|
+
prev._nonReactive.beforeLoadPromise = void 0;
|
|
770
|
+
prev._nonReactive.loadPromise?.resolve();
|
|
771
|
+
return {
|
|
772
|
+
...prev,
|
|
773
|
+
error: err,
|
|
774
|
+
status: "error",
|
|
775
|
+
isFetching: false,
|
|
776
|
+
updatedAt: Date.now(),
|
|
777
|
+
abortController: new AbortController()
|
|
778
|
+
};
|
|
779
|
+
});
|
|
780
|
+
};
|
|
781
|
+
this.isBeforeLoadSsr = (innerLoadContext, matchId, index, route) => {
|
|
782
|
+
const existingMatch = this.getMatch(matchId);
|
|
783
|
+
const parentMatchId = innerLoadContext.matches[index - 1]?.id;
|
|
784
|
+
const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
|
|
785
|
+
if (this.isShell()) {
|
|
786
|
+
existingMatch.ssr = matchId === root.rootRouteId;
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (parentMatch?.ssr === false) {
|
|
790
|
+
existingMatch.ssr = false;
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const parentOverride = (tempSsr2) => {
|
|
794
|
+
if (tempSsr2 === true && parentMatch?.ssr === "data-only") {
|
|
795
|
+
return "data-only";
|
|
712
796
|
}
|
|
797
|
+
return tempSsr2;
|
|
713
798
|
};
|
|
714
|
-
const
|
|
715
|
-
|
|
799
|
+
const defaultSsr = this.options.defaultSsr ?? true;
|
|
800
|
+
if (route.options.ssr === void 0) {
|
|
801
|
+
existingMatch.ssr = parentOverride(defaultSsr);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
if (typeof route.options.ssr !== "function") {
|
|
805
|
+
existingMatch.ssr = parentOverride(route.options.ssr);
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
const { search, params } = this.getMatch(matchId);
|
|
809
|
+
const ssrFnContext = {
|
|
810
|
+
search: makeMaybe(search, existingMatch.searchError),
|
|
811
|
+
params: makeMaybe(params, existingMatch.paramsError),
|
|
812
|
+
location: innerLoadContext.location,
|
|
813
|
+
matches: innerLoadContext.matches.map((match) => ({
|
|
814
|
+
index: match.index,
|
|
815
|
+
pathname: match.pathname,
|
|
816
|
+
fullPath: match.fullPath,
|
|
817
|
+
staticData: match.staticData,
|
|
818
|
+
id: match.id,
|
|
819
|
+
routeId: match.routeId,
|
|
820
|
+
search: makeMaybe(match.search, match.searchError),
|
|
821
|
+
params: makeMaybe(match.params, match.paramsError),
|
|
822
|
+
ssr: match.ssr
|
|
823
|
+
}))
|
|
716
824
|
};
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
825
|
+
const tempSsr = route.options.ssr(ssrFnContext);
|
|
826
|
+
if (utils.isPromise(tempSsr)) {
|
|
827
|
+
return tempSsr.then((ssr) => {
|
|
828
|
+
existingMatch.ssr = parentOverride(ssr ?? defaultSsr);
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
existingMatch.ssr = parentOverride(tempSsr ?? defaultSsr);
|
|
832
|
+
return;
|
|
833
|
+
};
|
|
834
|
+
this.setupPendingTimeout = (innerLoadContext, matchId, route) => {
|
|
835
|
+
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
836
|
+
const shouldPending = !!(innerLoadContext.onReady && !this.isServer && !this.resolvePreload(innerLoadContext, matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? this.options?.defaultPendingComponent));
|
|
837
|
+
const match = this.getMatch(matchId);
|
|
838
|
+
if (shouldPending && match._nonReactive.pendingTimeout === void 0) {
|
|
839
|
+
const pendingTimeout = setTimeout(() => {
|
|
840
|
+
this.triggerOnReady(innerLoadContext);
|
|
841
|
+
}, pendingMs);
|
|
842
|
+
match._nonReactive.pendingTimeout = pendingTimeout;
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
this.shouldExecuteBeforeLoad = (innerLoadContext, matchId, route) => {
|
|
846
|
+
const existingMatch = this.getMatch(matchId);
|
|
847
|
+
if (!existingMatch._nonReactive.beforeLoadPromise && !existingMatch._nonReactive.loaderPromise)
|
|
848
|
+
return true;
|
|
849
|
+
this.setupPendingTimeout(innerLoadContext, matchId, route);
|
|
850
|
+
const then = () => {
|
|
851
|
+
let shouldExecuteBeforeLoad = true;
|
|
852
|
+
const match = this.getMatch(matchId);
|
|
853
|
+
if (match.status === "error") {
|
|
854
|
+
shouldExecuteBeforeLoad = true;
|
|
855
|
+
} else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
|
|
856
|
+
this.handleRedirectAndNotFound(innerLoadContext, match, match.error);
|
|
857
|
+
}
|
|
858
|
+
return shouldExecuteBeforeLoad;
|
|
859
|
+
};
|
|
860
|
+
return existingMatch._nonReactive.beforeLoadPromise ? existingMatch._nonReactive.beforeLoadPromise.then(then) : then();
|
|
861
|
+
};
|
|
862
|
+
this.executeBeforeLoad = (innerLoadContext, matchId, index, route) => {
|
|
863
|
+
const match = this.getMatch(matchId);
|
|
864
|
+
match._nonReactive.beforeLoadPromise = utils.createControlledPromise();
|
|
865
|
+
const prevLoadPromise = match._nonReactive.loadPromise;
|
|
866
|
+
match._nonReactive.loadPromise = utils.createControlledPromise(() => {
|
|
867
|
+
prevLoadPromise?.resolve();
|
|
868
|
+
});
|
|
869
|
+
const { paramsError, searchError } = match;
|
|
870
|
+
if (paramsError) {
|
|
871
|
+
this.handleSerialError(
|
|
872
|
+
innerLoadContext,
|
|
873
|
+
index,
|
|
874
|
+
paramsError,
|
|
875
|
+
"PARSE_PARAMS"
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
if (searchError) {
|
|
879
|
+
this.handleSerialError(
|
|
880
|
+
innerLoadContext,
|
|
881
|
+
index,
|
|
882
|
+
searchError,
|
|
883
|
+
"VALIDATE_SEARCH"
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
this.setupPendingTimeout(innerLoadContext, matchId, route);
|
|
887
|
+
const abortController = new AbortController();
|
|
888
|
+
const parentMatchId = innerLoadContext.matches[index - 1]?.id;
|
|
889
|
+
const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
|
|
890
|
+
const parentMatchContext = parentMatch?.context ?? this.options.context ?? void 0;
|
|
891
|
+
const context = { ...parentMatchContext, ...match.__routeContext };
|
|
892
|
+
let isPending = false;
|
|
893
|
+
const pending = () => {
|
|
894
|
+
if (isPending) return;
|
|
895
|
+
isPending = true;
|
|
896
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
897
|
+
...prev,
|
|
898
|
+
isFetching: "beforeLoad",
|
|
899
|
+
fetchCount: prev.fetchCount + 1,
|
|
900
|
+
abortController,
|
|
901
|
+
context
|
|
902
|
+
}));
|
|
903
|
+
};
|
|
904
|
+
const resolve = () => {
|
|
905
|
+
match._nonReactive.beforeLoadPromise?.resolve();
|
|
906
|
+
match._nonReactive.beforeLoadPromise = void 0;
|
|
907
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
908
|
+
...prev,
|
|
909
|
+
isFetching: false
|
|
910
|
+
}));
|
|
911
|
+
};
|
|
912
|
+
if (!route.options.beforeLoad) {
|
|
913
|
+
store.batch(() => {
|
|
914
|
+
pending();
|
|
915
|
+
resolve();
|
|
916
|
+
});
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
const { search, params, cause } = match;
|
|
920
|
+
const preload = this.resolvePreload(innerLoadContext, matchId);
|
|
921
|
+
const beforeLoadFnContext = {
|
|
922
|
+
search,
|
|
923
|
+
abortController,
|
|
924
|
+
params,
|
|
925
|
+
preload,
|
|
926
|
+
context,
|
|
927
|
+
location: innerLoadContext.location,
|
|
928
|
+
navigate: (opts) => this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
|
|
929
|
+
buildLocation: this.buildLocation,
|
|
930
|
+
cause: preload ? "preload" : cause,
|
|
931
|
+
matches: innerLoadContext.matches
|
|
932
|
+
};
|
|
933
|
+
const updateContext = (beforeLoadContext2) => {
|
|
934
|
+
if (beforeLoadContext2 === void 0) {
|
|
935
|
+
store.batch(() => {
|
|
936
|
+
pending();
|
|
937
|
+
resolve();
|
|
938
|
+
});
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (redirect.isRedirect(beforeLoadContext2) || notFound.isNotFound(beforeLoadContext2)) {
|
|
942
|
+
pending();
|
|
943
|
+
this.handleSerialError(
|
|
944
|
+
innerLoadContext,
|
|
945
|
+
index,
|
|
946
|
+
beforeLoadContext2,
|
|
947
|
+
"BEFORE_LOAD"
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
store.batch(() => {
|
|
951
|
+
pending();
|
|
952
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
953
|
+
...prev,
|
|
954
|
+
__beforeLoadContext: beforeLoadContext2,
|
|
955
|
+
context: {
|
|
956
|
+
...prev.context,
|
|
957
|
+
...beforeLoadContext2
|
|
958
|
+
}
|
|
959
|
+
}));
|
|
960
|
+
resolve();
|
|
961
|
+
});
|
|
962
|
+
};
|
|
963
|
+
let beforeLoadContext;
|
|
964
|
+
try {
|
|
965
|
+
beforeLoadContext = route.options.beforeLoad(beforeLoadFnContext);
|
|
966
|
+
if (utils.isPromise(beforeLoadContext)) {
|
|
967
|
+
pending();
|
|
968
|
+
return beforeLoadContext.catch((err) => {
|
|
969
|
+
this.handleSerialError(innerLoadContext, index, err, "BEFORE_LOAD");
|
|
970
|
+
}).then(updateContext);
|
|
971
|
+
}
|
|
972
|
+
} catch (err) {
|
|
973
|
+
pending();
|
|
974
|
+
this.handleSerialError(innerLoadContext, index, err, "BEFORE_LOAD");
|
|
975
|
+
}
|
|
976
|
+
updateContext(beforeLoadContext);
|
|
977
|
+
return;
|
|
978
|
+
};
|
|
979
|
+
this.handleBeforeLoad = (innerLoadContext, index) => {
|
|
980
|
+
const { id: matchId, routeId } = innerLoadContext.matches[index];
|
|
981
|
+
const route = this.looseRoutesById[routeId];
|
|
982
|
+
const serverSsr = () => {
|
|
983
|
+
if (this.isServer) {
|
|
984
|
+
const maybePromise = this.isBeforeLoadSsr(
|
|
985
|
+
innerLoadContext,
|
|
986
|
+
matchId,
|
|
987
|
+
index,
|
|
988
|
+
route
|
|
989
|
+
);
|
|
990
|
+
if (utils.isPromise(maybePromise)) return maybePromise.then(queueExecution);
|
|
991
|
+
}
|
|
992
|
+
return queueExecution();
|
|
993
|
+
};
|
|
994
|
+
const queueExecution = () => {
|
|
995
|
+
if (this.shouldSkipLoader(matchId)) return;
|
|
996
|
+
const shouldExecuteBeforeLoadResult = this.shouldExecuteBeforeLoad(
|
|
997
|
+
innerLoadContext,
|
|
998
|
+
matchId,
|
|
999
|
+
route
|
|
1000
|
+
);
|
|
1001
|
+
return utils.isPromise(shouldExecuteBeforeLoadResult) ? shouldExecuteBeforeLoadResult.then(execute) : execute(shouldExecuteBeforeLoadResult);
|
|
1002
|
+
};
|
|
1003
|
+
const execute = (shouldExecuteBeforeLoad) => {
|
|
1004
|
+
if (shouldExecuteBeforeLoad) {
|
|
1005
|
+
return this.executeBeforeLoad(innerLoadContext, matchId, index, route);
|
|
1006
|
+
}
|
|
1007
|
+
return;
|
|
1008
|
+
};
|
|
1009
|
+
return serverSsr();
|
|
1010
|
+
};
|
|
1011
|
+
this.executeHead = (innerLoadContext, matchId, route) => {
|
|
1012
|
+
const match = this.getMatch(matchId);
|
|
1013
|
+
if (!match) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
if (!route.options.head && !route.options.scripts && !route.options.headers) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const assetContext = {
|
|
1020
|
+
matches: innerLoadContext.matches,
|
|
1021
|
+
match,
|
|
1022
|
+
params: match.params,
|
|
1023
|
+
loaderData: match.loaderData
|
|
1024
|
+
};
|
|
1025
|
+
return Promise.all([
|
|
1026
|
+
route.options.head?.(assetContext),
|
|
1027
|
+
route.options.scripts?.(assetContext),
|
|
1028
|
+
route.options.headers?.(assetContext)
|
|
1029
|
+
]).then(([headFnContent, scripts, headers]) => {
|
|
1030
|
+
const meta = headFnContent?.meta;
|
|
1031
|
+
const links = headFnContent?.links;
|
|
1032
|
+
const headScripts = headFnContent?.scripts;
|
|
1033
|
+
const styles = headFnContent?.styles;
|
|
1034
|
+
return {
|
|
1035
|
+
meta,
|
|
1036
|
+
links,
|
|
1037
|
+
headScripts,
|
|
1038
|
+
headers,
|
|
1039
|
+
scripts,
|
|
1040
|
+
styles
|
|
1041
|
+
};
|
|
1042
|
+
});
|
|
1043
|
+
};
|
|
1044
|
+
this.potentialPendingMinPromise = (matchId) => {
|
|
1045
|
+
const latestMatch = this.getMatch(matchId);
|
|
1046
|
+
return latestMatch._nonReactive.minPendingPromise;
|
|
1047
|
+
};
|
|
1048
|
+
this.getLoaderContext = (innerLoadContext, matchId, index, route) => {
|
|
1049
|
+
const parentMatchPromise = innerLoadContext.matchPromises[index - 1];
|
|
1050
|
+
const { params, loaderDeps, abortController, context, cause } = this.getMatch(matchId);
|
|
1051
|
+
const preload = this.resolvePreload(innerLoadContext, matchId);
|
|
1052
|
+
return {
|
|
1053
|
+
params,
|
|
1054
|
+
deps: loaderDeps,
|
|
1055
|
+
preload: !!preload,
|
|
1056
|
+
parentMatchPromise,
|
|
1057
|
+
abortController,
|
|
1058
|
+
context,
|
|
1059
|
+
location: innerLoadContext.location,
|
|
1060
|
+
navigate: (opts) => this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
|
|
1061
|
+
cause: preload ? "preload" : cause,
|
|
1062
|
+
route
|
|
1063
|
+
};
|
|
1064
|
+
};
|
|
1065
|
+
this.runLoader = async (innerLoadContext, matchId, index, route) => {
|
|
1066
|
+
try {
|
|
1067
|
+
try {
|
|
1068
|
+
if (!this.isServer || this.getMatch(matchId).ssr === true) {
|
|
1069
|
+
this.loadRouteChunk(route);
|
|
1070
|
+
}
|
|
1071
|
+
const loaderResult = route.options.loader?.(
|
|
1072
|
+
this.getLoaderContext(innerLoadContext, matchId, index, route)
|
|
1073
|
+
);
|
|
1074
|
+
const loaderResultIsPromise = route.options.loader && utils.isPromise(loaderResult);
|
|
1075
|
+
const willLoadSomething = !!(loaderResultIsPromise || route._lazyPromise || route._componentsPromise || route.options.head || route.options.scripts || route.options.headers || this.getMatch(matchId)._nonReactive.minPendingPromise);
|
|
1076
|
+
if (willLoadSomething) {
|
|
1077
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1078
|
+
...prev,
|
|
1079
|
+
isFetching: "loader"
|
|
1080
|
+
}));
|
|
1081
|
+
}
|
|
1082
|
+
if (route.options.loader) {
|
|
1083
|
+
const loaderData = loaderResultIsPromise ? await loaderResult : loaderResult;
|
|
1084
|
+
this.handleRedirectAndNotFound(
|
|
1085
|
+
innerLoadContext,
|
|
1086
|
+
this.getMatch(matchId),
|
|
1087
|
+
loaderData
|
|
1088
|
+
);
|
|
1089
|
+
if (loaderData !== void 0) {
|
|
1090
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1091
|
+
...prev,
|
|
1092
|
+
loaderData
|
|
1093
|
+
}));
|
|
727
1094
|
}
|
|
728
1095
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1096
|
+
if (route._lazyPromise) await route._lazyPromise;
|
|
1097
|
+
const headResult = this.executeHead(innerLoadContext, matchId, route);
|
|
1098
|
+
const head = headResult ? await headResult : void 0;
|
|
1099
|
+
const pendingPromise = this.potentialPendingMinPromise(matchId);
|
|
1100
|
+
if (pendingPromise) await pendingPromise;
|
|
1101
|
+
if (route._componentsPromise) await route._componentsPromise;
|
|
1102
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
732
1103
|
...prev,
|
|
733
|
-
|
|
1104
|
+
error: void 0,
|
|
1105
|
+
status: "success",
|
|
734
1106
|
isFetching: false,
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
loaderPromise: void 0
|
|
1107
|
+
updatedAt: Date.now(),
|
|
1108
|
+
...head
|
|
738
1109
|
}));
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1110
|
+
} catch (e) {
|
|
1111
|
+
let error = e;
|
|
1112
|
+
const pendingPromise = this.potentialPendingMinPromise(matchId);
|
|
1113
|
+
if (pendingPromise) await pendingPromise;
|
|
1114
|
+
this.handleRedirectAndNotFound(
|
|
1115
|
+
innerLoadContext,
|
|
1116
|
+
this.getMatch(matchId),
|
|
1117
|
+
e
|
|
1118
|
+
);
|
|
1119
|
+
try {
|
|
1120
|
+
route.options.onError?.(e);
|
|
1121
|
+
} catch (onErrorError) {
|
|
1122
|
+
error = onErrorError;
|
|
1123
|
+
this.handleRedirectAndNotFound(
|
|
1124
|
+
innerLoadContext,
|
|
1125
|
+
this.getMatch(matchId),
|
|
1126
|
+
onErrorError
|
|
1127
|
+
);
|
|
754
1128
|
}
|
|
1129
|
+
const headResult = this.executeHead(innerLoadContext, matchId, route);
|
|
1130
|
+
const head = headResult ? await headResult : void 0;
|
|
1131
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1132
|
+
...prev,
|
|
1133
|
+
error,
|
|
1134
|
+
status: "error",
|
|
1135
|
+
isFetching: false,
|
|
1136
|
+
...head
|
|
1137
|
+
}));
|
|
755
1138
|
}
|
|
756
|
-
}
|
|
757
|
-
const shouldSkipLoader = (matchId) => {
|
|
1139
|
+
} catch (err) {
|
|
758
1140
|
const match = this.getMatch(matchId);
|
|
759
|
-
if (
|
|
760
|
-
|
|
1141
|
+
if (match) {
|
|
1142
|
+
const headResult = this.executeHead(innerLoadContext, matchId, route);
|
|
1143
|
+
if (headResult) {
|
|
1144
|
+
const head = await headResult;
|
|
1145
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1146
|
+
...prev,
|
|
1147
|
+
...head
|
|
1148
|
+
}));
|
|
1149
|
+
}
|
|
1150
|
+
match._nonReactive.loaderPromise = void 0;
|
|
761
1151
|
}
|
|
1152
|
+
this.handleRedirectAndNotFound(innerLoadContext, match, err);
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
this.loadRouteMatch = async (innerLoadContext, index) => {
|
|
1156
|
+
const { id: matchId, routeId } = innerLoadContext.matches[index];
|
|
1157
|
+
let loaderShouldRunAsync = false;
|
|
1158
|
+
let loaderIsRunningAsync = false;
|
|
1159
|
+
const route = this.looseRoutesById[routeId];
|
|
1160
|
+
const prevMatch = this.getMatch(matchId);
|
|
1161
|
+
if (this.shouldSkipLoader(matchId)) {
|
|
762
1162
|
if (this.isServer) {
|
|
763
|
-
|
|
764
|
-
|
|
1163
|
+
const headResult = this.executeHead(innerLoadContext, matchId, route);
|
|
1164
|
+
if (headResult) {
|
|
1165
|
+
const head = await headResult;
|
|
1166
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1167
|
+
...prev,
|
|
1168
|
+
...head
|
|
1169
|
+
}));
|
|
765
1170
|
}
|
|
1171
|
+
return this.getMatch(matchId);
|
|
766
1172
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1173
|
+
} else if (prevMatch._nonReactive.loaderPromise) {
|
|
1174
|
+
if (prevMatch.status === "success" && !innerLoadContext.sync && !prevMatch.preload) {
|
|
1175
|
+
return this.getMatch(matchId);
|
|
1176
|
+
}
|
|
1177
|
+
await prevMatch._nonReactive.loaderPromise;
|
|
1178
|
+
const match2 = this.getMatch(matchId);
|
|
1179
|
+
if (match2.error) {
|
|
1180
|
+
this.handleRedirectAndNotFound(innerLoadContext, match2, match2.error);
|
|
1181
|
+
}
|
|
1182
|
+
} else {
|
|
1183
|
+
const age = Date.now() - this.getMatch(matchId).updatedAt;
|
|
1184
|
+
const preload = this.resolvePreload(innerLoadContext, matchId);
|
|
1185
|
+
const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
|
|
1186
|
+
const shouldReloadOption = route.options.shouldReload;
|
|
1187
|
+
const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(
|
|
1188
|
+
this.getLoaderContext(innerLoadContext, matchId, index, route)
|
|
1189
|
+
) : shouldReloadOption;
|
|
1190
|
+
const nextPreload = !!preload && !this.state.matches.some((d) => d.id === matchId);
|
|
1191
|
+
const match2 = this.getMatch(matchId);
|
|
1192
|
+
match2._nonReactive.loaderPromise = utils.createControlledPromise();
|
|
1193
|
+
if (nextPreload !== match2.preload) {
|
|
1194
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1195
|
+
...prev,
|
|
1196
|
+
preload: nextPreload
|
|
1197
|
+
}));
|
|
1198
|
+
}
|
|
1199
|
+
const { status, invalid } = this.getMatch(matchId);
|
|
1200
|
+
loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
|
|
1201
|
+
if (preload && route.options.preload === false) ;
|
|
1202
|
+
else if (loaderShouldRunAsync && !innerLoadContext.sync) {
|
|
1203
|
+
loaderIsRunningAsync = true;
|
|
772
1204
|
(async () => {
|
|
773
1205
|
try {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
err.routerCode = routerCode;
|
|
781
|
-
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
782
|
-
handleRedirectAndNotFound(this.getMatch(matchId), err);
|
|
783
|
-
try {
|
|
784
|
-
route.options.onError?.(err);
|
|
785
|
-
} catch (errorHandlerErr) {
|
|
786
|
-
err = errorHandlerErr;
|
|
787
|
-
handleRedirectAndNotFound(this.getMatch(matchId), err);
|
|
788
|
-
}
|
|
789
|
-
updateMatch(matchId, (prev) => {
|
|
790
|
-
prev.beforeLoadPromise?.resolve();
|
|
791
|
-
prev.loadPromise?.resolve();
|
|
792
|
-
return {
|
|
793
|
-
...prev,
|
|
794
|
-
error: err,
|
|
795
|
-
status: "error",
|
|
796
|
-
isFetching: false,
|
|
797
|
-
updatedAt: Date.now(),
|
|
798
|
-
abortController: new AbortController(),
|
|
799
|
-
beforeLoadPromise: void 0
|
|
800
|
-
};
|
|
801
|
-
});
|
|
802
|
-
};
|
|
803
|
-
for (const [index, { id: matchId, routeId }] of matches.entries()) {
|
|
804
|
-
const existingMatch = this.getMatch(matchId);
|
|
805
|
-
const parentMatchId = matches[index - 1]?.id;
|
|
806
|
-
const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
|
|
807
|
-
const route = this.looseRoutesById[routeId];
|
|
808
|
-
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
809
|
-
if (this.isServer) {
|
|
810
|
-
let ssr;
|
|
811
|
-
if (this.isShell()) {
|
|
812
|
-
ssr = matchId === root.rootRouteId;
|
|
813
|
-
} else {
|
|
814
|
-
const defaultSsr = this.options.defaultSsr ?? true;
|
|
815
|
-
if (parentMatch?.ssr === false) {
|
|
816
|
-
ssr = false;
|
|
817
|
-
} else {
|
|
818
|
-
let tempSsr;
|
|
819
|
-
if (route.options.ssr === void 0) {
|
|
820
|
-
tempSsr = defaultSsr;
|
|
821
|
-
} else if (typeof route.options.ssr === "function") {
|
|
822
|
-
let makeMaybe = function(value, error) {
|
|
823
|
-
if (error) {
|
|
824
|
-
return { status: "error", error };
|
|
825
|
-
}
|
|
826
|
-
return { status: "success", value };
|
|
827
|
-
};
|
|
828
|
-
const { search, params } = this.getMatch(matchId);
|
|
829
|
-
const ssrFnContext = {
|
|
830
|
-
search: makeMaybe(search, existingMatch.searchError),
|
|
831
|
-
params: makeMaybe(params, existingMatch.paramsError),
|
|
832
|
-
location,
|
|
833
|
-
matches: matches.map((match) => ({
|
|
834
|
-
index: match.index,
|
|
835
|
-
pathname: match.pathname,
|
|
836
|
-
fullPath: match.fullPath,
|
|
837
|
-
staticData: match.staticData,
|
|
838
|
-
id: match.id,
|
|
839
|
-
routeId: match.routeId,
|
|
840
|
-
search: makeMaybe(match.search, match.searchError),
|
|
841
|
-
params: makeMaybe(match.params, match.paramsError),
|
|
842
|
-
ssr: match.ssr
|
|
843
|
-
}))
|
|
844
|
-
};
|
|
845
|
-
tempSsr = await route.options.ssr(ssrFnContext) ?? defaultSsr;
|
|
846
|
-
} else {
|
|
847
|
-
tempSsr = route.options.ssr;
|
|
848
|
-
}
|
|
849
|
-
if (tempSsr === true && parentMatch?.ssr === "data-only") {
|
|
850
|
-
ssr = "data-only";
|
|
851
|
-
} else {
|
|
852
|
-
ssr = tempSsr;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
updateMatch(matchId, (prev) => ({
|
|
857
|
-
...prev,
|
|
858
|
-
ssr
|
|
859
|
-
}));
|
|
860
|
-
}
|
|
861
|
-
if (shouldSkipLoader(matchId)) {
|
|
862
|
-
continue;
|
|
863
|
-
}
|
|
864
|
-
const shouldPending = !!(onReady && !this.isServer && !resolvePreload(matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? this.options?.defaultPendingComponent));
|
|
865
|
-
let executeBeforeLoad = true;
|
|
866
|
-
const setupPendingTimeout = () => {
|
|
867
|
-
if (shouldPending && this.getMatch(matchId).pendingTimeout === void 0) {
|
|
868
|
-
const pendingTimeout = setTimeout(() => {
|
|
869
|
-
try {
|
|
870
|
-
triggerOnReady();
|
|
871
|
-
} catch {
|
|
872
|
-
}
|
|
873
|
-
}, pendingMs);
|
|
874
|
-
updateMatch(matchId, (prev) => ({
|
|
875
|
-
...prev,
|
|
876
|
-
pendingTimeout
|
|
877
|
-
}));
|
|
878
|
-
}
|
|
879
|
-
};
|
|
880
|
-
if (
|
|
881
|
-
// If we are in the middle of a load, either of these will be present
|
|
882
|
-
// (not to be confused with `loadPromise`, which is always defined)
|
|
883
|
-
existingMatch.beforeLoadPromise || existingMatch.loaderPromise
|
|
884
|
-
) {
|
|
885
|
-
setupPendingTimeout();
|
|
886
|
-
await existingMatch.beforeLoadPromise;
|
|
887
|
-
const match = this.getMatch(matchId);
|
|
888
|
-
if (match.status === "error") {
|
|
889
|
-
executeBeforeLoad = true;
|
|
890
|
-
} else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
|
|
891
|
-
handleRedirectAndNotFound(match, match.error);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
if (executeBeforeLoad) {
|
|
895
|
-
try {
|
|
896
|
-
updateMatch(matchId, (prev) => {
|
|
897
|
-
const prevLoadPromise = prev.loadPromise;
|
|
898
|
-
return {
|
|
899
|
-
...prev,
|
|
900
|
-
loadPromise: utils.createControlledPromise(() => {
|
|
901
|
-
prevLoadPromise?.resolve();
|
|
902
|
-
}),
|
|
903
|
-
beforeLoadPromise: utils.createControlledPromise()
|
|
904
|
-
};
|
|
905
|
-
});
|
|
906
|
-
const { paramsError, searchError } = this.getMatch(matchId);
|
|
907
|
-
if (paramsError) {
|
|
908
|
-
handleSerialError(index, paramsError, "PARSE_PARAMS");
|
|
909
|
-
}
|
|
910
|
-
if (searchError) {
|
|
911
|
-
handleSerialError(index, searchError, "VALIDATE_SEARCH");
|
|
912
|
-
}
|
|
913
|
-
setupPendingTimeout();
|
|
914
|
-
const abortController = new AbortController();
|
|
915
|
-
const parentMatchContext = parentMatch?.context ?? this.options.context ?? {};
|
|
916
|
-
updateMatch(matchId, (prev) => ({
|
|
917
|
-
...prev,
|
|
918
|
-
isFetching: "beforeLoad",
|
|
919
|
-
fetchCount: prev.fetchCount + 1,
|
|
920
|
-
abortController,
|
|
921
|
-
context: {
|
|
922
|
-
...parentMatchContext,
|
|
923
|
-
...prev.__routeContext
|
|
924
|
-
}
|
|
925
|
-
}));
|
|
926
|
-
const { search, params, context, cause } = this.getMatch(matchId);
|
|
927
|
-
const preload = resolvePreload(matchId);
|
|
928
|
-
const beforeLoadFnContext = {
|
|
929
|
-
search,
|
|
930
|
-
abortController,
|
|
931
|
-
params,
|
|
932
|
-
preload,
|
|
933
|
-
context,
|
|
934
|
-
location,
|
|
935
|
-
navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
|
|
936
|
-
buildLocation: this.buildLocation,
|
|
937
|
-
cause: preload ? "preload" : cause,
|
|
938
|
-
matches
|
|
939
|
-
};
|
|
940
|
-
const beforeLoadContext = await route.options.beforeLoad?.(beforeLoadFnContext);
|
|
941
|
-
if (redirect.isRedirect(beforeLoadContext) || notFound.isNotFound(beforeLoadContext)) {
|
|
942
|
-
handleSerialError(index, beforeLoadContext, "BEFORE_LOAD");
|
|
943
|
-
}
|
|
944
|
-
updateMatch(matchId, (prev) => {
|
|
945
|
-
return {
|
|
946
|
-
...prev,
|
|
947
|
-
__beforeLoadContext: beforeLoadContext,
|
|
948
|
-
context: {
|
|
949
|
-
...parentMatchContext,
|
|
950
|
-
...prev.__routeContext,
|
|
951
|
-
...beforeLoadContext
|
|
952
|
-
},
|
|
953
|
-
abortController
|
|
954
|
-
};
|
|
955
|
-
});
|
|
956
|
-
} catch (err) {
|
|
957
|
-
handleSerialError(index, err, "BEFORE_LOAD");
|
|
958
|
-
}
|
|
959
|
-
updateMatch(matchId, (prev) => {
|
|
960
|
-
prev.beforeLoadPromise?.resolve();
|
|
961
|
-
return {
|
|
962
|
-
...prev,
|
|
963
|
-
beforeLoadPromise: void 0,
|
|
964
|
-
isFetching: false
|
|
965
|
-
};
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
970
|
-
const matchPromises = [];
|
|
971
|
-
validResolvedMatches.forEach(({ id: matchId, routeId }, index) => {
|
|
972
|
-
matchPromises.push(
|
|
973
|
-
(async () => {
|
|
974
|
-
let loaderShouldRunAsync = false;
|
|
975
|
-
let loaderIsRunningAsync = false;
|
|
976
|
-
const route = this.looseRoutesById[routeId];
|
|
977
|
-
const executeHead = async () => {
|
|
978
|
-
const match = this.getMatch(matchId);
|
|
979
|
-
if (!match) {
|
|
980
|
-
return;
|
|
981
|
-
}
|
|
982
|
-
const assetContext = {
|
|
983
|
-
matches,
|
|
984
|
-
match,
|
|
985
|
-
params: match.params,
|
|
986
|
-
loaderData: match.loaderData
|
|
987
|
-
};
|
|
988
|
-
const headFnContent = await route.options.head?.(assetContext);
|
|
989
|
-
const meta = headFnContent?.meta;
|
|
990
|
-
const links = headFnContent?.links;
|
|
991
|
-
const headScripts = headFnContent?.scripts;
|
|
992
|
-
const styles = headFnContent?.styles;
|
|
993
|
-
const scripts = await route.options.scripts?.(assetContext);
|
|
994
|
-
const headers = await route.options.headers?.(assetContext);
|
|
995
|
-
return {
|
|
996
|
-
meta,
|
|
997
|
-
links,
|
|
998
|
-
headScripts,
|
|
999
|
-
headers,
|
|
1000
|
-
scripts,
|
|
1001
|
-
styles
|
|
1002
|
-
};
|
|
1003
|
-
};
|
|
1004
|
-
const potentialPendingMinPromise = async () => {
|
|
1005
|
-
const latestMatch = this.getMatch(matchId);
|
|
1006
|
-
if (latestMatch.minPendingPromise) {
|
|
1007
|
-
await latestMatch.minPendingPromise;
|
|
1008
|
-
}
|
|
1009
|
-
};
|
|
1010
|
-
const prevMatch = this.getMatch(matchId);
|
|
1011
|
-
if (shouldSkipLoader(matchId)) {
|
|
1012
|
-
if (this.isServer) {
|
|
1013
|
-
const head = await executeHead();
|
|
1014
|
-
updateMatch(matchId, (prev) => ({
|
|
1015
|
-
...prev,
|
|
1016
|
-
...head
|
|
1017
|
-
}));
|
|
1018
|
-
return this.getMatch(matchId);
|
|
1019
|
-
}
|
|
1020
|
-
} else if (prevMatch.loaderPromise) {
|
|
1021
|
-
if (prevMatch.status === "success" && !sync && !prevMatch.preload) {
|
|
1022
|
-
return this.getMatch(matchId);
|
|
1023
|
-
}
|
|
1024
|
-
await prevMatch.loaderPromise;
|
|
1025
|
-
const match = this.getMatch(matchId);
|
|
1026
|
-
if (match.error) {
|
|
1027
|
-
handleRedirectAndNotFound(match, match.error);
|
|
1028
|
-
}
|
|
1029
|
-
} else {
|
|
1030
|
-
const parentMatchPromise = matchPromises[index - 1];
|
|
1031
|
-
const getLoaderContext = () => {
|
|
1032
|
-
const {
|
|
1033
|
-
params,
|
|
1034
|
-
loaderDeps,
|
|
1035
|
-
abortController,
|
|
1036
|
-
context,
|
|
1037
|
-
cause
|
|
1038
|
-
} = this.getMatch(matchId);
|
|
1039
|
-
const preload2 = resolvePreload(matchId);
|
|
1040
|
-
return {
|
|
1041
|
-
params,
|
|
1042
|
-
deps: loaderDeps,
|
|
1043
|
-
preload: !!preload2,
|
|
1044
|
-
parentMatchPromise,
|
|
1045
|
-
abortController,
|
|
1046
|
-
context,
|
|
1047
|
-
location,
|
|
1048
|
-
navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
|
|
1049
|
-
cause: preload2 ? "preload" : cause,
|
|
1050
|
-
route
|
|
1051
|
-
};
|
|
1052
|
-
};
|
|
1053
|
-
const age = Date.now() - this.getMatch(matchId).updatedAt;
|
|
1054
|
-
const preload = resolvePreload(matchId);
|
|
1055
|
-
const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
|
|
1056
|
-
const shouldReloadOption = route.options.shouldReload;
|
|
1057
|
-
const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(getLoaderContext()) : shouldReloadOption;
|
|
1058
|
-
updateMatch(matchId, (prev) => ({
|
|
1059
|
-
...prev,
|
|
1060
|
-
loaderPromise: utils.createControlledPromise(),
|
|
1061
|
-
preload: !!preload && !this.state.matches.some((d) => d.id === matchId)
|
|
1062
|
-
}));
|
|
1063
|
-
const runLoader = async () => {
|
|
1064
|
-
try {
|
|
1065
|
-
try {
|
|
1066
|
-
if (!this.isServer || this.isServer && this.getMatch(matchId).ssr === true) {
|
|
1067
|
-
this.loadRouteChunk(route);
|
|
1068
|
-
}
|
|
1069
|
-
updateMatch(matchId, (prev) => ({
|
|
1070
|
-
...prev,
|
|
1071
|
-
isFetching: "loader"
|
|
1072
|
-
}));
|
|
1073
|
-
const loaderData = await route.options.loader?.(getLoaderContext());
|
|
1074
|
-
handleRedirectAndNotFound(
|
|
1075
|
-
this.getMatch(matchId),
|
|
1076
|
-
loaderData
|
|
1077
|
-
);
|
|
1078
|
-
updateMatch(matchId, (prev) => ({
|
|
1079
|
-
...prev,
|
|
1080
|
-
loaderData
|
|
1081
|
-
}));
|
|
1082
|
-
await route._lazyPromise;
|
|
1083
|
-
const head = await executeHead();
|
|
1084
|
-
await potentialPendingMinPromise();
|
|
1085
|
-
await route._componentsPromise;
|
|
1086
|
-
updateMatch(matchId, (prev) => ({
|
|
1087
|
-
...prev,
|
|
1088
|
-
error: void 0,
|
|
1089
|
-
status: "success",
|
|
1090
|
-
isFetching: false,
|
|
1091
|
-
updatedAt: Date.now(),
|
|
1092
|
-
...head
|
|
1093
|
-
}));
|
|
1094
|
-
} catch (e) {
|
|
1095
|
-
let error = e;
|
|
1096
|
-
await potentialPendingMinPromise();
|
|
1097
|
-
handleRedirectAndNotFound(this.getMatch(matchId), e);
|
|
1098
|
-
try {
|
|
1099
|
-
route.options.onError?.(e);
|
|
1100
|
-
} catch (onErrorError) {
|
|
1101
|
-
error = onErrorError;
|
|
1102
|
-
handleRedirectAndNotFound(
|
|
1103
|
-
this.getMatch(matchId),
|
|
1104
|
-
onErrorError
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1107
|
-
const head = await executeHead();
|
|
1108
|
-
updateMatch(matchId, (prev) => ({
|
|
1109
|
-
...prev,
|
|
1110
|
-
error,
|
|
1111
|
-
status: "error",
|
|
1112
|
-
isFetching: false,
|
|
1113
|
-
...head
|
|
1114
|
-
}));
|
|
1115
|
-
}
|
|
1116
|
-
} catch (err) {
|
|
1117
|
-
const head = await executeHead();
|
|
1118
|
-
updateMatch(matchId, (prev) => ({
|
|
1119
|
-
...prev,
|
|
1120
|
-
loaderPromise: void 0,
|
|
1121
|
-
...head
|
|
1122
|
-
}));
|
|
1123
|
-
handleRedirectAndNotFound(this.getMatch(matchId), err);
|
|
1124
|
-
}
|
|
1125
|
-
};
|
|
1126
|
-
const { status, invalid } = this.getMatch(matchId);
|
|
1127
|
-
loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
|
|
1128
|
-
if (preload && route.options.preload === false) {
|
|
1129
|
-
} else if (loaderShouldRunAsync && !sync) {
|
|
1130
|
-
loaderIsRunningAsync = true;
|
|
1131
|
-
(async () => {
|
|
1132
|
-
try {
|
|
1133
|
-
await runLoader();
|
|
1134
|
-
const { loaderPromise, loadPromise } = this.getMatch(matchId);
|
|
1135
|
-
loaderPromise?.resolve();
|
|
1136
|
-
loadPromise?.resolve();
|
|
1137
|
-
updateMatch(matchId, (prev) => ({
|
|
1138
|
-
...prev,
|
|
1139
|
-
loaderPromise: void 0
|
|
1140
|
-
}));
|
|
1141
|
-
} catch (err) {
|
|
1142
|
-
if (redirect.isRedirect(err)) {
|
|
1143
|
-
await this.navigate(err.options);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
})();
|
|
1147
|
-
} else if (status !== "success" || loaderShouldRunAsync && sync) {
|
|
1148
|
-
await runLoader();
|
|
1149
|
-
} else {
|
|
1150
|
-
const head = await executeHead();
|
|
1151
|
-
updateMatch(matchId, (prev) => ({
|
|
1152
|
-
...prev,
|
|
1153
|
-
...head
|
|
1154
|
-
}));
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
if (!loaderIsRunningAsync) {
|
|
1158
|
-
const { loaderPromise, loadPromise } = this.getMatch(matchId);
|
|
1159
|
-
loaderPromise?.resolve();
|
|
1160
|
-
loadPromise?.resolve();
|
|
1161
|
-
}
|
|
1162
|
-
updateMatch(matchId, (prev) => {
|
|
1163
|
-
clearTimeout(prev.pendingTimeout);
|
|
1164
|
-
return {
|
|
1165
|
-
...prev,
|
|
1166
|
-
isFetching: loaderIsRunningAsync ? prev.isFetching : false,
|
|
1167
|
-
loaderPromise: loaderIsRunningAsync ? prev.loaderPromise : void 0,
|
|
1168
|
-
invalid: false,
|
|
1169
|
-
pendingTimeout: void 0,
|
|
1170
|
-
_dehydrated: void 0
|
|
1171
|
-
};
|
|
1172
|
-
});
|
|
1173
|
-
return this.getMatch(matchId);
|
|
1174
|
-
})()
|
|
1175
|
-
);
|
|
1176
|
-
});
|
|
1177
|
-
await Promise.all(matchPromises);
|
|
1178
|
-
resolveAll();
|
|
1206
|
+
await this.runLoader(innerLoadContext, matchId, index, route);
|
|
1207
|
+
const match3 = this.getMatch(matchId);
|
|
1208
|
+
match3._nonReactive.loaderPromise?.resolve();
|
|
1209
|
+
match3._nonReactive.loadPromise?.resolve();
|
|
1210
|
+
match3._nonReactive.loaderPromise = void 0;
|
|
1179
1211
|
} catch (err) {
|
|
1180
|
-
|
|
1212
|
+
if (redirect.isRedirect(err)) {
|
|
1213
|
+
await this.navigate(err.options);
|
|
1214
|
+
}
|
|
1181
1215
|
}
|
|
1182
1216
|
})();
|
|
1183
|
-
})
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
if (
|
|
1188
|
-
await
|
|
1217
|
+
} else if (status !== "success" || loaderShouldRunAsync && innerLoadContext.sync) {
|
|
1218
|
+
await this.runLoader(innerLoadContext, matchId, index, route);
|
|
1219
|
+
} else {
|
|
1220
|
+
const headResult = this.executeHead(innerLoadContext, matchId, route);
|
|
1221
|
+
if (headResult) {
|
|
1222
|
+
const head = await headResult;
|
|
1223
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1224
|
+
...prev,
|
|
1225
|
+
...head
|
|
1226
|
+
}));
|
|
1189
1227
|
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
const match = this.getMatch(matchId);
|
|
1231
|
+
if (!loaderIsRunningAsync) {
|
|
1232
|
+
match._nonReactive.loaderPromise?.resolve();
|
|
1233
|
+
match._nonReactive.loadPromise?.resolve();
|
|
1234
|
+
}
|
|
1235
|
+
clearTimeout(match._nonReactive.pendingTimeout);
|
|
1236
|
+
match._nonReactive.pendingTimeout = void 0;
|
|
1237
|
+
if (!loaderIsRunningAsync) match._nonReactive.loaderPromise = void 0;
|
|
1238
|
+
match._nonReactive.dehydrated = void 0;
|
|
1239
|
+
const nextIsFetching = loaderIsRunningAsync ? match.isFetching : false;
|
|
1240
|
+
if (nextIsFetching !== match.isFetching || match.invalid !== false) {
|
|
1241
|
+
innerLoadContext.updateMatch(matchId, (prev) => ({
|
|
1242
|
+
...prev,
|
|
1243
|
+
isFetching: nextIsFetching,
|
|
1244
|
+
invalid: false
|
|
1245
|
+
}));
|
|
1246
|
+
}
|
|
1247
|
+
return this.getMatch(matchId);
|
|
1248
|
+
};
|
|
1249
|
+
this.loadMatches = async (baseContext) => {
|
|
1250
|
+
const innerLoadContext = baseContext;
|
|
1251
|
+
innerLoadContext.updateMatch ??= this.updateMatch;
|
|
1252
|
+
innerLoadContext.matchPromises = [];
|
|
1253
|
+
if (!this.isServer && this.state.matches.some((d) => d._forcePending)) {
|
|
1254
|
+
this.triggerOnReady(innerLoadContext);
|
|
1255
|
+
}
|
|
1256
|
+
try {
|
|
1257
|
+
for (let i = 0; i < innerLoadContext.matches.length; i++) {
|
|
1258
|
+
const beforeLoad = this.handleBeforeLoad(innerLoadContext, i);
|
|
1259
|
+
if (utils.isPromise(beforeLoad)) await beforeLoad;
|
|
1260
|
+
}
|
|
1261
|
+
const max = innerLoadContext.firstBadMatchIndex ?? innerLoadContext.matches.length;
|
|
1262
|
+
for (let i = 0; i < max; i++) {
|
|
1263
|
+
innerLoadContext.matchPromises.push(
|
|
1264
|
+
this.loadRouteMatch(innerLoadContext, i)
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
await Promise.all(innerLoadContext.matchPromises);
|
|
1268
|
+
const readyPromise = this.triggerOnReady(innerLoadContext);
|
|
1269
|
+
if (utils.isPromise(readyPromise)) await readyPromise;
|
|
1270
|
+
} catch (err) {
|
|
1271
|
+
if (notFound.isNotFound(err) && !innerLoadContext.preload) {
|
|
1272
|
+
const readyPromise = this.triggerOnReady(innerLoadContext);
|
|
1273
|
+
if (utils.isPromise(readyPromise)) await readyPromise;
|
|
1274
|
+
throw err;
|
|
1275
|
+
}
|
|
1276
|
+
if (redirect.isRedirect(err)) {
|
|
1190
1277
|
throw err;
|
|
1191
1278
|
}
|
|
1192
1279
|
}
|
|
1193
|
-
return matches;
|
|
1280
|
+
return innerLoadContext.matches;
|
|
1194
1281
|
};
|
|
1195
1282
|
this.invalidate = (opts) => {
|
|
1196
1283
|
const invalidate = (d) => {
|
|
@@ -1198,7 +1285,7 @@ class RouterCore {
|
|
|
1198
1285
|
return {
|
|
1199
1286
|
...d,
|
|
1200
1287
|
invalid: true,
|
|
1201
|
-
...opts?.forcePending || d.status === "error" ? { status: "pending", error: void 0 } :
|
|
1288
|
+
...opts?.forcePending || d.status === "error" ? { status: "pending", error: void 0 } : void 0
|
|
1202
1289
|
};
|
|
1203
1290
|
}
|
|
1204
1291
|
return d;
|
|
@@ -1257,27 +1344,35 @@ class RouterCore {
|
|
|
1257
1344
|
this.clearCache({ filter });
|
|
1258
1345
|
};
|
|
1259
1346
|
this.loadRouteChunk = (route) => {
|
|
1260
|
-
if (route._lazyPromise === void 0) {
|
|
1347
|
+
if (!route._lazyLoaded && route._lazyPromise === void 0) {
|
|
1261
1348
|
if (route.lazyFn) {
|
|
1262
1349
|
route._lazyPromise = route.lazyFn().then((lazyRoute) => {
|
|
1263
1350
|
const { id: _id, ...options2 } = lazyRoute.options;
|
|
1264
1351
|
Object.assign(route.options, options2);
|
|
1352
|
+
route._lazyLoaded = true;
|
|
1353
|
+
route._lazyPromise = void 0;
|
|
1265
1354
|
});
|
|
1266
1355
|
} else {
|
|
1267
|
-
route.
|
|
1356
|
+
route._lazyLoaded = true;
|
|
1268
1357
|
}
|
|
1269
1358
|
}
|
|
1270
|
-
if (route._componentsPromise === void 0) {
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1359
|
+
if (!route._componentsLoaded && route._componentsPromise === void 0) {
|
|
1360
|
+
const loadComponents = () => {
|
|
1361
|
+
const preloads = [];
|
|
1362
|
+
for (const type of componentTypes) {
|
|
1363
|
+
const preload = route.options[type]?.preload;
|
|
1364
|
+
if (preload) preloads.push(preload());
|
|
1365
|
+
}
|
|
1366
|
+
if (preloads.length)
|
|
1367
|
+
return Promise.all(preloads).then(() => {
|
|
1368
|
+
route._componentsLoaded = true;
|
|
1369
|
+
route._componentsPromise = void 0;
|
|
1370
|
+
});
|
|
1371
|
+
route._componentsLoaded = true;
|
|
1372
|
+
route._componentsPromise = void 0;
|
|
1373
|
+
return;
|
|
1374
|
+
};
|
|
1375
|
+
route._componentsPromise = route._lazyPromise ? route._lazyPromise.then(loadComponents) : loadComponents();
|
|
1281
1376
|
}
|
|
1282
1377
|
return route._componentsPromise;
|
|
1283
1378
|
};
|
|
@@ -1375,12 +1470,10 @@ class RouterCore {
|
|
|
1375
1470
|
}
|
|
1376
1471
|
return match;
|
|
1377
1472
|
};
|
|
1378
|
-
this._handleNotFound = (
|
|
1379
|
-
updateMatch = this.updateMatch
|
|
1380
|
-
} = {}) => {
|
|
1473
|
+
this._handleNotFound = (innerLoadContext, err) => {
|
|
1381
1474
|
const routeCursor = this.routesById[err.routeId ?? ""] ?? this.routeTree;
|
|
1382
1475
|
const matchesByRouteId = {};
|
|
1383
|
-
for (const match of matches) {
|
|
1476
|
+
for (const match of innerLoadContext.matches) {
|
|
1384
1477
|
matchesByRouteId[match.routeId] = match;
|
|
1385
1478
|
}
|
|
1386
1479
|
if (!routeCursor.options.notFoundComponent && this.options?.defaultNotFoundComponent) {
|
|
@@ -1395,7 +1488,7 @@ class RouterCore {
|
|
|
1395
1488
|
matchForRoute,
|
|
1396
1489
|
"Could not find match for route: " + routeCursor.id
|
|
1397
1490
|
);
|
|
1398
|
-
updateMatch(matchForRoute.id, (prev) => ({
|
|
1491
|
+
innerLoadContext.updateMatch(matchForRoute.id, (prev) => ({
|
|
1399
1492
|
...prev,
|
|
1400
1493
|
status: "notFound",
|
|
1401
1494
|
error: err,
|
|
@@ -1403,9 +1496,7 @@ class RouterCore {
|
|
|
1403
1496
|
}));
|
|
1404
1497
|
if (err.routerCode === "BEFORE_LOAD" && routeCursor.parentRoute) {
|
|
1405
1498
|
err.routeId = routeCursor.parentRoute.id;
|
|
1406
|
-
this._handleNotFound(
|
|
1407
|
-
updateMatch
|
|
1408
|
-
});
|
|
1499
|
+
this._handleNotFound(innerLoadContext, err);
|
|
1409
1500
|
}
|
|
1410
1501
|
};
|
|
1411
1502
|
this.hasNotFoundMatch = () => {
|
|
@@ -1495,16 +1586,16 @@ class RouterCore {
|
|
|
1495
1586
|
const matches = [];
|
|
1496
1587
|
const getParentContext = (parentMatch) => {
|
|
1497
1588
|
const parentMatchId = parentMatch?.id;
|
|
1498
|
-
const parentContext = !parentMatchId ? this.options.context ??
|
|
1589
|
+
const parentContext = !parentMatchId ? this.options.context ?? void 0 : parentMatch.context ?? this.options.context ?? void 0;
|
|
1499
1590
|
return parentContext;
|
|
1500
1591
|
};
|
|
1501
1592
|
matchedRoutes.forEach((route, index) => {
|
|
1502
1593
|
const parentMatch = matches[index - 1];
|
|
1503
1594
|
const [preMatchSearch, strictMatchSearch, searchError] = (() => {
|
|
1504
1595
|
const parentSearch = parentMatch?.search ?? next.search;
|
|
1505
|
-
const parentStrictSearch = parentMatch?._strictSearch ??
|
|
1596
|
+
const parentStrictSearch = parentMatch?._strictSearch ?? void 0;
|
|
1506
1597
|
try {
|
|
1507
|
-
const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ??
|
|
1598
|
+
const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ?? void 0;
|
|
1508
1599
|
return [
|
|
1509
1600
|
{
|
|
1510
1601
|
...parentSearch,
|
|
@@ -1574,7 +1665,10 @@ class RouterCore {
|
|
|
1574
1665
|
isFetching: false,
|
|
1575
1666
|
error: void 0,
|
|
1576
1667
|
paramsError: parseErrors[index],
|
|
1577
|
-
__routeContext:
|
|
1668
|
+
__routeContext: void 0,
|
|
1669
|
+
_nonReactive: {
|
|
1670
|
+
loadPromise: utils.createControlledPromise()
|
|
1671
|
+
},
|
|
1578
1672
|
__beforeLoadContext: void 0,
|
|
1579
1673
|
context: {},
|
|
1580
1674
|
abortController: new AbortController(),
|
|
@@ -1588,7 +1682,6 @@ class RouterCore {
|
|
|
1588
1682
|
headScripts: void 0,
|
|
1589
1683
|
meta: void 0,
|
|
1590
1684
|
staticData: route.options.staticData || {},
|
|
1591
|
-
loadPromise: utils.createControlledPromise(),
|
|
1592
1685
|
fullPath: route.fullPath
|
|
1593
1686
|
};
|
|
1594
1687
|
}
|
|
@@ -1610,19 +1703,21 @@ class RouterCore {
|
|
|
1610
1703
|
if (!existingMatch && opts?._buildLocation !== true) {
|
|
1611
1704
|
const parentMatch = matches[index - 1];
|
|
1612
1705
|
const parentContext = getParentContext(parentMatch);
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1706
|
+
if (route.options.context) {
|
|
1707
|
+
const contextFnContext = {
|
|
1708
|
+
deps: match.loaderDeps,
|
|
1709
|
+
params: match.params,
|
|
1710
|
+
context: parentContext ?? {},
|
|
1711
|
+
location: next,
|
|
1712
|
+
navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
|
|
1713
|
+
buildLocation: this.buildLocation,
|
|
1714
|
+
cause: match.cause,
|
|
1715
|
+
abortController: match.abortController,
|
|
1716
|
+
preload: !!match.preload,
|
|
1717
|
+
matches
|
|
1718
|
+
};
|
|
1719
|
+
match.__routeContext = route.options.context(contextFnContext) ?? void 0;
|
|
1720
|
+
}
|
|
1626
1721
|
match.context = {
|
|
1627
1722
|
...parentContext,
|
|
1628
1723
|
...match.__routeContext,
|
|
@@ -1637,6 +1732,12 @@ class SearchParamError extends Error {
|
|
|
1637
1732
|
}
|
|
1638
1733
|
class PathParamError extends Error {
|
|
1639
1734
|
}
|
|
1735
|
+
function makeMaybe(value, error) {
|
|
1736
|
+
if (error) {
|
|
1737
|
+
return { status: "error", error };
|
|
1738
|
+
}
|
|
1739
|
+
return { status: "success", value };
|
|
1740
|
+
}
|
|
1640
1741
|
const normalize = (str) => str.endsWith("/") && str.length > 1 ? str.slice(0, -1) : str;
|
|
1641
1742
|
function comparePaths(a, b) {
|
|
1642
1743
|
return normalize(a) === normalize(b);
|
|
@@ -1925,7 +2026,7 @@ function applySearchMiddleware({
|
|
|
1925
2026
|
try {
|
|
1926
2027
|
const validatedSearch = {
|
|
1927
2028
|
...result,
|
|
1928
|
-
...validateSearch(route.options.validateSearch, result) ??
|
|
2029
|
+
...validateSearch(route.options.validateSearch, result) ?? void 0
|
|
1929
2030
|
};
|
|
1930
2031
|
return validatedSearch;
|
|
1931
2032
|
} catch {
|