@tanstack/router-core 1.142.11 → 1.143.3
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/load-matches.cjs +34 -34
- package/dist/cjs/load-matches.cjs.map +1 -1
- package/dist/cjs/router.cjs +6 -2
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/esm/load-matches.js +34 -34
- package/dist/esm/load-matches.js.map +1 -1
- package/dist/esm/router.js +6 -2
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/load-matches.ts +46 -36
- package/src/router.ts +25 -2
package/src/load-matches.ts
CHANGED
|
@@ -683,8 +683,6 @@ const runLoader = async (
|
|
|
683
683
|
// so we need to wait for it to resolve before
|
|
684
684
|
// we can use the options
|
|
685
685
|
if (route._lazyPromise) await route._lazyPromise
|
|
686
|
-
const headResult = executeHead(inner, matchId, route)
|
|
687
|
-
const head = headResult ? await headResult : undefined
|
|
688
686
|
const pendingPromise = match._nonReactive.minPendingPromise
|
|
689
687
|
if (pendingPromise) await pendingPromise
|
|
690
688
|
|
|
@@ -697,7 +695,6 @@ const runLoader = async (
|
|
|
697
695
|
status: 'success',
|
|
698
696
|
isFetching: false,
|
|
699
697
|
updatedAt: Date.now(),
|
|
700
|
-
...head,
|
|
701
698
|
}))
|
|
702
699
|
} catch (e) {
|
|
703
700
|
let error = e
|
|
@@ -721,28 +718,17 @@ const runLoader = async (
|
|
|
721
718
|
onErrorError,
|
|
722
719
|
)
|
|
723
720
|
}
|
|
724
|
-
const headResult = executeHead(inner, matchId, route)
|
|
725
|
-
const head = headResult ? await headResult : undefined
|
|
726
721
|
inner.updateMatch(matchId, (prev) => ({
|
|
727
722
|
...prev,
|
|
728
723
|
error,
|
|
729
724
|
status: 'error',
|
|
730
725
|
isFetching: false,
|
|
731
|
-
...head,
|
|
732
726
|
}))
|
|
733
727
|
}
|
|
734
728
|
} catch (err) {
|
|
735
729
|
const match = inner.router.getMatch(matchId)
|
|
736
730
|
// in case of a redirecting match during preload, the match does not exist
|
|
737
731
|
if (match) {
|
|
738
|
-
const headResult = executeHead(inner, matchId, route)
|
|
739
|
-
if (headResult) {
|
|
740
|
-
const head = await headResult
|
|
741
|
-
inner.updateMatch(matchId, (prev) => ({
|
|
742
|
-
...prev,
|
|
743
|
-
...head,
|
|
744
|
-
}))
|
|
745
|
-
}
|
|
746
732
|
match._nonReactive.loaderPromise = undefined
|
|
747
733
|
}
|
|
748
734
|
handleRedirectAndNotFound(inner, match, err)
|
|
@@ -767,14 +753,6 @@ const loadRouteMatch = async (
|
|
|
767
753
|
|
|
768
754
|
if (shouldSkipLoader(inner, matchId)) {
|
|
769
755
|
if (inner.router.isServer) {
|
|
770
|
-
const headResult = executeHead(inner, matchId, route)
|
|
771
|
-
if (headResult) {
|
|
772
|
-
const head = await headResult
|
|
773
|
-
inner.updateMatch(matchId, (prev) => ({
|
|
774
|
-
...prev,
|
|
775
|
-
...head,
|
|
776
|
-
}))
|
|
777
|
-
}
|
|
778
756
|
return inner.router.getMatch(matchId)!
|
|
779
757
|
}
|
|
780
758
|
} else {
|
|
@@ -852,18 +830,6 @@ const loadRouteMatch = async (
|
|
|
852
830
|
})()
|
|
853
831
|
} else if (status !== 'success' || (loaderShouldRunAsync && inner.sync)) {
|
|
854
832
|
await runLoader(inner, matchId, index, route)
|
|
855
|
-
} else {
|
|
856
|
-
// if the loader did not run, still update head.
|
|
857
|
-
// reason: parent's beforeLoad may have changed the route context
|
|
858
|
-
// and only now do we know the route context (and that the loader would not run)
|
|
859
|
-
const headResult = executeHead(inner, matchId, route)
|
|
860
|
-
if (headResult) {
|
|
861
|
-
const head = await headResult
|
|
862
|
-
inner.updateMatch(matchId, (prev) => ({
|
|
863
|
-
...prev,
|
|
864
|
-
...head,
|
|
865
|
-
}))
|
|
866
|
-
}
|
|
867
833
|
}
|
|
868
834
|
}
|
|
869
835
|
}
|
|
@@ -931,7 +897,52 @@ export async function loadMatches(arg: {
|
|
|
931
897
|
for (let i = 0; i < max; i++) {
|
|
932
898
|
inner.matchPromises.push(loadRouteMatch(inner, i))
|
|
933
899
|
}
|
|
934
|
-
|
|
900
|
+
// Use allSettled to ensure all loaders complete regardless of success/failure
|
|
901
|
+
const results = await Promise.allSettled(inner.matchPromises)
|
|
902
|
+
|
|
903
|
+
const failures = results
|
|
904
|
+
// TODO when we drop support for TS 5.4, we can use the built-in type guard for PromiseRejectedResult
|
|
905
|
+
.filter(
|
|
906
|
+
(result): result is PromiseRejectedResult =>
|
|
907
|
+
result.status === 'rejected',
|
|
908
|
+
)
|
|
909
|
+
.map((result) => result.reason)
|
|
910
|
+
|
|
911
|
+
// Find first redirect (throw immediately) or notFound (throw after head execution)
|
|
912
|
+
let firstNotFound: unknown
|
|
913
|
+
for (const err of failures) {
|
|
914
|
+
if (isRedirect(err)) {
|
|
915
|
+
throw err
|
|
916
|
+
}
|
|
917
|
+
if (!firstNotFound && isNotFound(err)) {
|
|
918
|
+
firstNotFound = err
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// serially execute head functions after all loaders have completed (successfully or not)
|
|
923
|
+
// Each head execution is wrapped in try-catch to ensure all heads run even if one fails
|
|
924
|
+
for (const match of inner.matches) {
|
|
925
|
+
const { id: matchId, routeId } = match
|
|
926
|
+
const route = inner.router.looseRoutesById[routeId]!
|
|
927
|
+
try {
|
|
928
|
+
const headResult = executeHead(inner, matchId, route)
|
|
929
|
+
if (headResult) {
|
|
930
|
+
const head = await headResult
|
|
931
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
932
|
+
...prev,
|
|
933
|
+
...head,
|
|
934
|
+
}))
|
|
935
|
+
}
|
|
936
|
+
} catch (err) {
|
|
937
|
+
// Log error but continue executing other head functions
|
|
938
|
+
console.error(`Error executing head for route ${routeId}:`, err)
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// Throw notFound after head execution
|
|
943
|
+
if (firstNotFound) {
|
|
944
|
+
throw firstNotFound
|
|
945
|
+
}
|
|
935
946
|
|
|
936
947
|
const readyPromise = triggerOnReady(inner)
|
|
937
948
|
if (isPromise(readyPromise)) await readyPromise
|
|
@@ -945,7 +956,6 @@ export async function loadMatches(arg: {
|
|
|
945
956
|
throw err
|
|
946
957
|
}
|
|
947
958
|
}
|
|
948
|
-
|
|
949
959
|
return inner.matches
|
|
950
960
|
}
|
|
951
961
|
|
package/src/router.ts
CHANGED
|
@@ -1177,6 +1177,7 @@ export class RouterCore<
|
|
|
1177
1177
|
// Before we do any processing, we need to allow rewrites to modify the URL
|
|
1178
1178
|
// build up the full URL by combining the href from history with the router's origin
|
|
1179
1179
|
const fullUrl = new URL(href, this.origin)
|
|
1180
|
+
|
|
1180
1181
|
const url = executeRewriteInput(this.rewrite, fullUrl)
|
|
1181
1182
|
|
|
1182
1183
|
const parsedSearch = this.options.parseSearch(url.search)
|
|
@@ -1187,11 +1188,33 @@ export class RouterCore<
|
|
|
1187
1188
|
|
|
1188
1189
|
const fullPath = url.href.replace(url.origin, '')
|
|
1189
1190
|
|
|
1191
|
+
// Save the internal pathname for route matching (before output rewrite)
|
|
1192
|
+
const internalPathname = url.pathname
|
|
1193
|
+
|
|
1194
|
+
// Compute publicHref by applying the output rewrite.
|
|
1195
|
+
//
|
|
1196
|
+
// The publicHref represents the URL as it should appear in the browser.
|
|
1197
|
+
// This must match what buildLocation computes for the same logical route,
|
|
1198
|
+
// otherwise the server-side redirect check will see a mismatch and trigger
|
|
1199
|
+
// an infinite redirect loop.
|
|
1200
|
+
//
|
|
1201
|
+
// We always apply the output rewrite (not conditionally) because the
|
|
1202
|
+
// incoming URL may have already been transformed by external middleware
|
|
1203
|
+
// before reaching the router. In that case, the input rewrite has nothing
|
|
1204
|
+
// to do, but we still need the output rewrite to reconstruct the correct
|
|
1205
|
+
// public-facing URL.
|
|
1206
|
+
//
|
|
1207
|
+
// Clone the URL to avoid mutating the one used for route matching.
|
|
1208
|
+
const urlForOutput = new URL(url.href)
|
|
1209
|
+
const rewrittenUrl = executeRewriteOutput(this.rewrite, urlForOutput)
|
|
1210
|
+
const publicHref =
|
|
1211
|
+
rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash
|
|
1212
|
+
|
|
1190
1213
|
return {
|
|
1191
1214
|
href: fullPath,
|
|
1192
|
-
publicHref
|
|
1215
|
+
publicHref,
|
|
1193
1216
|
url: url,
|
|
1194
|
-
pathname: decodePath(
|
|
1217
|
+
pathname: decodePath(internalPathname),
|
|
1195
1218
|
searchStr,
|
|
1196
1219
|
search: replaceEqualDeep(previousLocation?.search, parsedSearch) as any,
|
|
1197
1220
|
hash: url.hash.split('#').reverse()[0] ?? '',
|