diff --git a/e2e/react-start/basic/src/routeTree.gen.ts b/e2e/react-start/basic/src/routeTree.gen.ts index a4c81f99f38..ba75e2d05fb 100644 --- a/e2e/react-start/basic/src/routeTree.gen.ts +++ b/e2e/react-start/basic/src/routeTree.gen.ts @@ -33,7 +33,6 @@ import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/ import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' import { Route as NotFoundViaLoaderRouteImport } from './routes/not-found/via-loader' -import { Route as NotFoundViaHeadRouteImport } from './routes/not-found/via-head' import { Route as NotFoundViaBeforeLoadRouteImport } from './routes/not-found/via-beforeLoad' import { Route as MultiCookieRedirectTargetRouteImport } from './routes/multi-cookie-redirect/target' import { Route as ApiUsersRouteImport } from './routes/api.users' @@ -174,11 +173,6 @@ const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({ path: '/via-loader', getParentRoute: () => NotFoundRouteRoute, } as any) -const NotFoundViaHeadRoute = NotFoundViaHeadRouteImport.update({ - id: '/via-head', - path: '/via-head', - getParentRoute: () => NotFoundRouteRoute, -} as any) const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', @@ -285,7 +279,6 @@ export interface FileRoutesByFullPath { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -323,7 +316,6 @@ export interface FileRoutesByTo { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/search-params/default': typeof SearchParamsDefaultRoute @@ -366,7 +358,6 @@ export interface FileRoutesById { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -410,7 +401,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/redirect/$target' @@ -448,7 +438,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/search-params/default' @@ -490,7 +479,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/redirect/$target' @@ -710,13 +698,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof NotFoundViaLoaderRouteImport parentRoute: typeof NotFoundRouteRoute } - '/not-found/via-head': { - id: '/not-found/via-head' - path: '/via-head' - fullPath: '/not-found/via-head' - preLoaderRoute: typeof NotFoundViaHeadRouteImport - parentRoute: typeof NotFoundRouteRoute - } '/not-found/via-beforeLoad': { id: '/not-found/via-beforeLoad' path: '/via-beforeLoad' @@ -841,14 +822,12 @@ declare module '@tanstack/react-router' { interface NotFoundRouteRouteChildren { NotFoundViaBeforeLoadRoute: typeof NotFoundViaBeforeLoadRoute - NotFoundViaHeadRoute: typeof NotFoundViaHeadRoute NotFoundViaLoaderRoute: typeof NotFoundViaLoaderRoute NotFoundIndexRoute: typeof NotFoundIndexRoute } const NotFoundRouteRouteChildren: NotFoundRouteRouteChildren = { NotFoundViaBeforeLoadRoute: NotFoundViaBeforeLoadRoute, - NotFoundViaHeadRoute: NotFoundViaHeadRoute, NotFoundViaLoaderRoute: NotFoundViaLoaderRoute, NotFoundIndexRoute: NotFoundIndexRoute, } diff --git a/e2e/react-start/basic/src/routes/not-found/index.tsx b/e2e/react-start/basic/src/routes/not-found/index.tsx index 722813fca36..e754f83c74b 100644 --- a/e2e/react-start/basic/src/routes/not-found/index.tsx +++ b/e2e/react-start/basic/src/routes/not-found/index.tsx @@ -25,16 +25,6 @@ export const Route = createFileRoute('/not-found/')({ via-loader -
- - via-head - -
) }, diff --git a/e2e/react-start/basic/src/routes/not-found/via-head.tsx b/e2e/react-start/basic/src/routes/not-found/via-head.tsx deleted file mode 100644 index 7cd09f9fa31..00000000000 --- a/e2e/react-start/basic/src/routes/not-found/via-head.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { createFileRoute, notFound } from '@tanstack/react-router' - -export const Route = createFileRoute('/not-found/via-head')({ - head: () => { - throw notFound() - }, - component: RouteComponent, - notFoundComponent: () => { - return ( -
- Not Found "/not-found/via-head"! -
- ) - }, -}) - -function RouteComponent() { - return ( -
- Hello "/not-found/via-head"! -
- ) -} diff --git a/e2e/react-start/basic/tests/not-found.spec.ts b/e2e/react-start/basic/tests/not-found.spec.ts index 0b5acc3b782..3e3bffd0944 100644 --- a/e2e/react-start/basic/tests/not-found.spec.ts +++ b/e2e/react-start/basic/tests/not-found.spec.ts @@ -26,7 +26,7 @@ test.describe('not-found', () => { test.describe('throw notFound()', () => { const navigationTestMatrix = combinate({ // TODO beforeLoad! - thrower: [/* 'beforeLoad',*/ 'head', 'loader'] as const, + thrower: [/* 'beforeLoad',*/ 'loader'] as const, preload: [false, true] as const, }) @@ -58,7 +58,7 @@ test.describe('not-found', () => { const directVisitTestMatrix = combinate({ // TODO beforeLoad! - thrower: [/* 'beforeLoad',*/ 'head', 'loader'] as const, + thrower: [/* 'beforeLoad',*/ 'loader'] as const, }) directVisitTestMatrix.forEach(({ thrower }) => { diff --git a/e2e/react-start/basic/vite.config.ts b/e2e/react-start/basic/vite.config.ts index 944dfecc761..55c716bdb82 100644 --- a/e2e/react-start/basic/vite.config.ts +++ b/e2e/react-start/basic/vite.config.ts @@ -21,7 +21,6 @@ const prerenderConfiguration = { '/redirect', '/i-do-not-exist', '/not-found/via-beforeLoad', - '/not-found/via-head', '/not-found/via-loader', '/users', ].some((p) => page.path.includes(p)), diff --git a/e2e/solid-start/basic/src/routeTree.gen.ts b/e2e/solid-start/basic/src/routeTree.gen.ts index 9919aecb003..553ced91ff7 100644 --- a/e2e/solid-start/basic/src/routeTree.gen.ts +++ b/e2e/solid-start/basic/src/routeTree.gen.ts @@ -33,7 +33,6 @@ import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/ import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' import { Route as NotFoundViaLoaderRouteImport } from './routes/not-found/via-loader' -import { Route as NotFoundViaHeadRouteImport } from './routes/not-found/via-head' import { Route as NotFoundViaBeforeLoadRouteImport } from './routes/not-found/via-beforeLoad' import { Route as MultiCookieRedirectTargetRouteImport } from './routes/multi-cookie-redirect/target' import { Route as ApiUsersRouteImport } from './routes/api/users' @@ -174,11 +173,6 @@ const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({ path: '/via-loader', getParentRoute: () => NotFoundRouteRoute, } as any) -const NotFoundViaHeadRoute = NotFoundViaHeadRouteImport.update({ - id: '/via-head', - path: '/via-head', - getParentRoute: () => NotFoundRouteRoute, -} as any) const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', @@ -287,7 +281,6 @@ export interface FileRoutesByFullPath { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -325,7 +318,6 @@ export interface FileRoutesByTo { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/search-params/default': typeof SearchParamsDefaultRoute @@ -369,7 +361,6 @@ export interface FileRoutesById { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -413,7 +404,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/redirect/$target' @@ -451,7 +441,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/search-params/default' @@ -494,7 +483,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/redirect/$target' @@ -715,13 +703,6 @@ declare module '@tanstack/solid-router' { preLoaderRoute: typeof NotFoundViaLoaderRouteImport parentRoute: typeof NotFoundRouteRoute } - '/not-found/via-head': { - id: '/not-found/via-head' - path: '/via-head' - fullPath: '/not-found/via-head' - preLoaderRoute: typeof NotFoundViaHeadRouteImport - parentRoute: typeof NotFoundRouteRoute - } '/not-found/via-beforeLoad': { id: '/not-found/via-beforeLoad' path: '/via-beforeLoad' @@ -846,14 +827,12 @@ declare module '@tanstack/solid-router' { interface NotFoundRouteRouteChildren { NotFoundViaBeforeLoadRoute: typeof NotFoundViaBeforeLoadRoute - NotFoundViaHeadRoute: typeof NotFoundViaHeadRoute NotFoundViaLoaderRoute: typeof NotFoundViaLoaderRoute NotFoundIndexRoute: typeof NotFoundIndexRoute } const NotFoundRouteRouteChildren: NotFoundRouteRouteChildren = { NotFoundViaBeforeLoadRoute: NotFoundViaBeforeLoadRoute, - NotFoundViaHeadRoute: NotFoundViaHeadRoute, NotFoundViaLoaderRoute: NotFoundViaLoaderRoute, NotFoundIndexRoute: NotFoundIndexRoute, } diff --git a/e2e/solid-start/basic/src/routes/not-found/index.tsx b/e2e/solid-start/basic/src/routes/not-found/index.tsx index 54eff41247c..34c8ef61469 100644 --- a/e2e/solid-start/basic/src/routes/not-found/index.tsx +++ b/e2e/solid-start/basic/src/routes/not-found/index.tsx @@ -25,16 +25,6 @@ export const Route = createFileRoute('/not-found/')({ via-loader -
- - via-head - -
) }, diff --git a/e2e/solid-start/basic/src/routes/not-found/via-head.tsx b/e2e/solid-start/basic/src/routes/not-found/via-head.tsx deleted file mode 100644 index 51806db45e1..00000000000 --- a/e2e/solid-start/basic/src/routes/not-found/via-head.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { createFileRoute, notFound } from '@tanstack/solid-router' - -export const Route = createFileRoute('/not-found/via-head')({ - head: () => { - throw notFound() - }, - component: RouteComponent, - notFoundComponent: () => { - return ( -
- Not Found "/not-found/via-head"! -
- ) - }, -}) - -function RouteComponent() { - return ( -
- Hello "/not-found/via-head"! -
- ) -} diff --git a/e2e/solid-start/basic/tests/not-found.spec.ts b/e2e/solid-start/basic/tests/not-found.spec.ts index 1bed8e991c9..2962f2bafa4 100644 --- a/e2e/solid-start/basic/tests/not-found.spec.ts +++ b/e2e/solid-start/basic/tests/not-found.spec.ts @@ -26,7 +26,7 @@ test.describe('not-found', () => { test.describe('throw notFound()', () => { const navigationTestMatrix = combinate({ // TODO beforeLoad! - thrower: [/* 'beforeLoad',*/ 'head', 'loader'] as const, + thrower: [/* 'beforeLoad',*/ 'loader'] as const, preload: [false, true] as const, }) @@ -57,7 +57,7 @@ test.describe('not-found', () => { const directVisitTestMatrix = combinate({ // TODO beforeLoad! - thrower: [/* 'beforeLoad',*/ 'head', 'loader'] as const, + thrower: [/* 'beforeLoad',*/ 'loader'] as const, }) directVisitTestMatrix.forEach(({ thrower }) => { diff --git a/e2e/solid-start/basic/vite.config.ts b/e2e/solid-start/basic/vite.config.ts index 28b1f563b6d..37a52a0ea3c 100644 --- a/e2e/solid-start/basic/vite.config.ts +++ b/e2e/solid-start/basic/vite.config.ts @@ -21,7 +21,6 @@ const prerenderConfiguration = { '/redirect', '/i-do-not-exist', '/not-found/via-beforeLoad', - '/not-found/via-head', '/not-found/via-loader', '/search-params/default', '/transition', diff --git a/e2e/vue-start/basic/src/routeTree.gen.ts b/e2e/vue-start/basic/src/routeTree.gen.ts index 7232919c5ee..aa30a6bac12 100644 --- a/e2e/vue-start/basic/src/routeTree.gen.ts +++ b/e2e/vue-start/basic/src/routeTree.gen.ts @@ -33,7 +33,6 @@ import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/ import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' import { Route as NotFoundViaLoaderRouteImport } from './routes/not-found/via-loader' -import { Route as NotFoundViaHeadRouteImport } from './routes/not-found/via-head' import { Route as NotFoundViaBeforeLoadRouteImport } from './routes/not-found/via-beforeLoad' import { Route as MultiCookieRedirectTargetRouteImport } from './routes/multi-cookie-redirect/target' import { Route as ApiUsersRouteImport } from './routes/api/users' @@ -172,11 +171,6 @@ const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({ path: '/via-loader', getParentRoute: () => NotFoundRouteRoute, } as any) -const NotFoundViaHeadRoute = NotFoundViaHeadRouteImport.update({ - id: '/via-head', - path: '/via-head', - getParentRoute: () => NotFoundRouteRoute, -} as any) const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', @@ -273,7 +267,6 @@ export interface FileRoutesByFullPath { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -309,7 +302,6 @@ export interface FileRoutesByTo { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/search-params/default': typeof SearchParamsDefaultRoute @@ -351,7 +343,6 @@ export interface FileRoutesById { '/api/users': typeof ApiUsersRouteWithChildren '/multi-cookie-redirect/target': typeof MultiCookieRedirectTargetRoute '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute - '/not-found/via-head': typeof NotFoundViaHeadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -393,7 +384,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/redirect/$target' @@ -429,7 +419,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/search-params/default' @@ -470,7 +459,6 @@ export interface FileRouteTypes { | '/api/users' | '/multi-cookie-redirect/target' | '/not-found/via-beforeLoad' - | '/not-found/via-head' | '/not-found/via-loader' | '/posts/$postId' | '/redirect/$target' @@ -687,13 +675,6 @@ declare module '@tanstack/vue-router' { preLoaderRoute: typeof NotFoundViaLoaderRouteImport parentRoute: typeof NotFoundRouteRoute } - '/not-found/via-head': { - id: '/not-found/via-head' - path: '/via-head' - fullPath: '/not-found/via-head' - preLoaderRoute: typeof NotFoundViaHeadRouteImport - parentRoute: typeof NotFoundRouteRoute - } '/not-found/via-beforeLoad': { id: '/not-found/via-beforeLoad' path: '/via-beforeLoad' @@ -804,14 +785,12 @@ declare module '@tanstack/vue-router' { interface NotFoundRouteRouteChildren { NotFoundViaBeforeLoadRoute: typeof NotFoundViaBeforeLoadRoute - NotFoundViaHeadRoute: typeof NotFoundViaHeadRoute NotFoundViaLoaderRoute: typeof NotFoundViaLoaderRoute NotFoundIndexRoute: typeof NotFoundIndexRoute } const NotFoundRouteRouteChildren: NotFoundRouteRouteChildren = { NotFoundViaBeforeLoadRoute: NotFoundViaBeforeLoadRoute, - NotFoundViaHeadRoute: NotFoundViaHeadRoute, NotFoundViaLoaderRoute: NotFoundViaLoaderRoute, NotFoundIndexRoute: NotFoundIndexRoute, } diff --git a/e2e/vue-start/basic/src/routes/not-found/index.tsx b/e2e/vue-start/basic/src/routes/not-found/index.tsx index 13cc6ee9245..9f7e3b4b330 100644 --- a/e2e/vue-start/basic/src/routes/not-found/index.tsx +++ b/e2e/vue-start/basic/src/routes/not-found/index.tsx @@ -25,16 +25,6 @@ export const Route = createFileRoute('/not-found/')({ via-loader -
- - via-head - -
) }, diff --git a/e2e/vue-start/basic/src/routes/not-found/via-head.tsx b/e2e/vue-start/basic/src/routes/not-found/via-head.tsx deleted file mode 100644 index 41966ab429e..00000000000 --- a/e2e/vue-start/basic/src/routes/not-found/via-head.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { createFileRoute, notFound } from '@tanstack/vue-router' - -export const Route = createFileRoute('/not-found/via-head')({ - head: () => { - throw notFound() - }, - component: RouteComponent, - notFoundComponent: () => { - return ( -
- Not Found "/not-found/via-head"! -
- ) - }, -}) - -function RouteComponent() { - return ( -
- Hello "/not-found/via-head"! -
- ) -} diff --git a/e2e/vue-start/basic/tests/not-found.spec.ts b/e2e/vue-start/basic/tests/not-found.spec.ts index 1bed8e991c9..2962f2bafa4 100644 --- a/e2e/vue-start/basic/tests/not-found.spec.ts +++ b/e2e/vue-start/basic/tests/not-found.spec.ts @@ -26,7 +26,7 @@ test.describe('not-found', () => { test.describe('throw notFound()', () => { const navigationTestMatrix = combinate({ // TODO beforeLoad! - thrower: [/* 'beforeLoad',*/ 'head', 'loader'] as const, + thrower: [/* 'beforeLoad',*/ 'loader'] as const, preload: [false, true] as const, }) @@ -57,7 +57,7 @@ test.describe('not-found', () => { const directVisitTestMatrix = combinate({ // TODO beforeLoad! - thrower: [/* 'beforeLoad',*/ 'head', 'loader'] as const, + thrower: [/* 'beforeLoad',*/ 'loader'] as const, }) directVisitTestMatrix.forEach(({ thrower }) => { diff --git a/e2e/vue-start/basic/vite.config.ts b/e2e/vue-start/basic/vite.config.ts index 0da7494f18d..13b694045ae 100644 --- a/e2e/vue-start/basic/vite.config.ts +++ b/e2e/vue-start/basic/vite.config.ts @@ -21,7 +21,6 @@ const prerenderConfiguration = { '/redirect', '/i-do-not-exist', '/not-found/via-beforeLoad', - '/not-found/via-head', '/not-found/via-loader', '/search-params', // search-param routes have dynamic content based on query params '/transition', diff --git a/packages/router-core/src/load-matches.ts b/packages/router-core/src/load-matches.ts index 2909d6d25a6..ec72cbfe441 100644 --- a/packages/router-core/src/load-matches.ts +++ b/packages/router-core/src/load-matches.ts @@ -683,8 +683,6 @@ const runLoader = async ( // so we need to wait for it to resolve before // we can use the options if (route._lazyPromise) await route._lazyPromise - const headResult = executeHead(inner, matchId, route) - const head = headResult ? await headResult : undefined const pendingPromise = match._nonReactive.minPendingPromise if (pendingPromise) await pendingPromise @@ -697,7 +695,6 @@ const runLoader = async ( status: 'success', isFetching: false, updatedAt: Date.now(), - ...head, })) } catch (e) { let error = e @@ -721,28 +718,17 @@ const runLoader = async ( onErrorError, ) } - const headResult = executeHead(inner, matchId, route) - const head = headResult ? await headResult : undefined inner.updateMatch(matchId, (prev) => ({ ...prev, error, status: 'error', isFetching: false, - ...head, })) } } catch (err) { const match = inner.router.getMatch(matchId) // in case of a redirecting match during preload, the match does not exist if (match) { - const headResult = executeHead(inner, matchId, route) - if (headResult) { - const head = await headResult - inner.updateMatch(matchId, (prev) => ({ - ...prev, - ...head, - })) - } match._nonReactive.loaderPromise = undefined } handleRedirectAndNotFound(inner, match, err) @@ -767,14 +753,6 @@ const loadRouteMatch = async ( if (shouldSkipLoader(inner, matchId)) { if (inner.router.isServer) { - const headResult = executeHead(inner, matchId, route) - if (headResult) { - const head = await headResult - inner.updateMatch(matchId, (prev) => ({ - ...prev, - ...head, - })) - } return inner.router.getMatch(matchId)! } } else { @@ -852,18 +830,6 @@ const loadRouteMatch = async ( })() } else if (status !== 'success' || (loaderShouldRunAsync && inner.sync)) { await runLoader(inner, matchId, index, route) - } else { - // if the loader did not run, still update head. - // reason: parent's beforeLoad may have changed the route context - // and only now do we know the route context (and that the loader would not run) - const headResult = executeHead(inner, matchId, route) - if (headResult) { - const head = await headResult - inner.updateMatch(matchId, (prev) => ({ - ...prev, - ...head, - })) - } } } } @@ -931,7 +897,52 @@ export async function loadMatches(arg: { for (let i = 0; i < max; i++) { inner.matchPromises.push(loadRouteMatch(inner, i)) } - await Promise.all(inner.matchPromises) + // Use allSettled to ensure all loaders complete regardless of success/failure + const results = await Promise.allSettled(inner.matchPromises) + + const failures = results + // TODO when we drop support for TS 5.4, we can use the built-in type guard for PromiseRejectedResult + .filter( + (result): result is PromiseRejectedResult => + result.status === 'rejected', + ) + .map((result) => result.reason) + + // Find first redirect (throw immediately) or notFound (throw after head execution) + let firstNotFound: unknown + for (const err of failures) { + if (isRedirect(err)) { + throw err + } + if (!firstNotFound && isNotFound(err)) { + firstNotFound = err + } + } + + // serially execute head functions after all loaders have completed (successfully or not) + // Each head execution is wrapped in try-catch to ensure all heads run even if one fails + for (const match of inner.matches) { + const { id: matchId, routeId } = match + const route = inner.router.looseRoutesById[routeId]! + try { + const headResult = executeHead(inner, matchId, route) + if (headResult) { + const head = await headResult + inner.updateMatch(matchId, (prev) => ({ + ...prev, + ...head, + })) + } + } catch (err) { + // Log error but continue executing other head functions + console.error(`Error executing head for route ${routeId}:`, err) + } + } + + // Throw notFound after head execution + if (firstNotFound) { + throw firstNotFound + } const readyPromise = triggerOnReady(inner) if (isPromise(readyPromise)) await readyPromise @@ -945,7 +956,6 @@ export async function loadMatches(arg: { throw err } } - return inner.matches }