Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
44f561c
fix(router-core,ssr-client): catch errors thrown from head
roduyemi Oct 9, 2025
b343aaa
chore(e2e): add test case for head not found to solid-start
roduyemi Oct 9, 2025
1c27c12
chore(router-core): remove recursive call when handling before load e…
roduyemi Oct 9, 2025
9729f07
fix(router-core): types in hydrate.test
roduyemi Oct 9, 2025
2b309c5
chore: add eol to hydrate.test
roduyemi Oct 9, 2025
5347508
feat(router-core): move executeHead to beforeLoad
roduyemi Oct 9, 2025
20b60af
chore: execute head functions
roduyemi Oct 27, 2025
1be11a3
Merge remote-tracking branch 'upstream/main' into head-404
roduyemi Oct 27, 2025
e53cf57
chore: only run excuteHead during SSR
roduyemi Oct 27, 2025
08c5f8e
fix: remove async on updateContext
roduyemi Oct 27, 2025
7cb7450
chore: execute head after loaders + add test to ensure correct error …
roduyemi Oct 28, 2025
254defe
chore: remove multiple loaders from via-head
roduyemi Oct 28, 2025
3abb562
chore: add via-loaders to test run
roduyemi Oct 28, 2025
5dd98c4
chore: add solid-start e2e via-loaders test
roduyemi Oct 28, 2025
fec4a1b
fix: load notFoundComponent with styles during before load error
roduyemi Oct 28, 2025
8238499
chore: remove matchId param from _handleNotFound
roduyemi Oct 28, 2025
366e4af
fix: check match.context before skipping head execution
roduyemi Oct 28, 2025
b12398d
chore: rename via-loaders to via-loader-with-context
roduyemi Oct 28, 2025
625c901
fix: update solid-router expected store updates
roduyemi Oct 28, 2025
d9b1951
chore: remove thenable
roduyemi Oct 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions e2e/react-start/basic/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ import { Route as SearchParamsLoaderThrowsRedirectRouteImport } from './routes/s
import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/default'
import { Route as RedirectTargetRouteImport } from './routes/redirect/$target'
import { Route as PostsPostIdRouteImport } from './routes/posts.$postId'
import { Route as NotFoundViaLoaderWithContextRouteImport } from './routes/not-found/via-loader-with-context'
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 ApiUsersRouteImport } from './routes/api.users'
import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2'
Expand Down Expand Up @@ -164,11 +166,22 @@ const PostsPostIdRoute = PostsPostIdRouteImport.update({
path: '/$postId',
getParentRoute: () => PostsRoute,
} as any)
const NotFoundViaLoaderWithContextRoute =
NotFoundViaLoaderWithContextRouteImport.update({
id: '/via-loader-with-context',
path: '/via-loader-with-context',
getParentRoute: () => NotFoundRouteRoute,
} as any)
const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({
id: '/via-loader',
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',
Expand Down Expand Up @@ -272,7 +285,9 @@ export interface FileRoutesByFullPath {
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
'/api/users': typeof ApiUsersRouteWithChildren
'/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute
'/not-found/via-head': typeof NotFoundViaHeadRoute
'/not-found/via-loader': typeof NotFoundViaLoaderRoute
'/not-found/via-loader-with-context': typeof NotFoundViaLoaderWithContextRoute
'/posts/$postId': typeof PostsPostIdRoute
'/redirect/$target': typeof RedirectTargetRouteWithChildren
'/search-params/default': typeof SearchParamsDefaultRoute
Expand Down Expand Up @@ -307,7 +322,9 @@ export interface FileRoutesByTo {
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
'/api/users': typeof ApiUsersRouteWithChildren
'/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute
'/not-found/via-head': typeof NotFoundViaHeadRoute
'/not-found/via-loader': typeof NotFoundViaLoaderRoute
'/not-found/via-loader-with-context': typeof NotFoundViaLoaderWithContextRoute
'/posts/$postId': typeof PostsPostIdRoute
'/search-params/default': typeof SearchParamsDefaultRoute
'/search-params/loader-throws-redirect': typeof SearchParamsLoaderThrowsRedirectRoute
Expand Down Expand Up @@ -347,7 +364,9 @@ export interface FileRoutesById {
'/_layout/_layout-2': typeof LayoutLayout2RouteWithChildren
'/api/users': typeof ApiUsersRouteWithChildren
'/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute
'/not-found/via-head': typeof NotFoundViaHeadRoute
'/not-found/via-loader': typeof NotFoundViaLoaderRoute
'/not-found/via-loader-with-context': typeof NotFoundViaLoaderWithContextRoute
'/posts/$postId': typeof PostsPostIdRoute
'/redirect/$target': typeof RedirectTargetRouteWithChildren
'/search-params/default': typeof SearchParamsDefaultRoute
Expand Down Expand Up @@ -389,7 +408,9 @@ export interface FileRouteTypes {
| '/대한민국'
| '/api/users'
| '/not-found/via-beforeLoad'
| '/not-found/via-head'
| '/not-found/via-loader'
| '/not-found/via-loader-with-context'
| '/posts/$postId'
| '/redirect/$target'
| '/search-params/default'
Expand Down Expand Up @@ -424,7 +445,9 @@ export interface FileRouteTypes {
| '/대한민국'
| '/api/users'
| '/not-found/via-beforeLoad'
| '/not-found/via-head'
| '/not-found/via-loader'
| '/not-found/via-loader-with-context'
| '/posts/$postId'
| '/search-params/default'
| '/search-params/loader-throws-redirect'
Expand Down Expand Up @@ -463,7 +486,9 @@ export interface FileRouteTypes {
| '/_layout/_layout-2'
| '/api/users'
| '/not-found/via-beforeLoad'
| '/not-found/via-head'
| '/not-found/via-loader'
| '/not-found/via-loader-with-context'
| '/posts/$postId'
| '/redirect/$target'
| '/search-params/default'
Expand Down Expand Up @@ -666,13 +691,27 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PostsPostIdRouteImport
parentRoute: typeof PostsRoute
}
'/not-found/via-loader-with-context': {
id: '/not-found/via-loader-with-context'
path: '/via-loader-with-context'
fullPath: '/not-found/via-loader-with-context'
preLoaderRoute: typeof NotFoundViaLoaderWithContextRouteImport
parentRoute: typeof NotFoundRouteRoute
}
'/not-found/via-loader': {
id: '/not-found/via-loader'
path: '/via-loader'
fullPath: '/not-found/via-loader'
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'
Expand Down Expand Up @@ -797,13 +836,17 @@ declare module '@tanstack/react-router' {

interface NotFoundRouteRouteChildren {
NotFoundViaBeforeLoadRoute: typeof NotFoundViaBeforeLoadRoute
NotFoundViaHeadRoute: typeof NotFoundViaHeadRoute
NotFoundViaLoaderRoute: typeof NotFoundViaLoaderRoute
NotFoundViaLoaderWithContextRoute: typeof NotFoundViaLoaderWithContextRoute
NotFoundIndexRoute: typeof NotFoundIndexRoute
}

const NotFoundRouteRouteChildren: NotFoundRouteRouteChildren = {
NotFoundViaBeforeLoadRoute: NotFoundViaBeforeLoadRoute,
NotFoundViaHeadRoute: NotFoundViaHeadRoute,
NotFoundViaLoaderRoute: NotFoundViaLoaderRoute,
NotFoundViaLoaderWithContextRoute: NotFoundViaLoaderWithContextRoute,
NotFoundIndexRoute: NotFoundIndexRoute,
}

Expand Down
20 changes: 20 additions & 0 deletions e2e/react-start/basic/src/routes/not-found/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ export const Route = createFileRoute('/not-found/')({
via-loader
</Link>
</div>
<div className="mb-2">
<Link
from={Route.fullPath}
to="./via-head"
preload={preload}
data-testid="via-head"
>
via-head
</Link>
</div>
<div className="mb-2">
<Link
from={Route.fullPath}
to="./via-loader-with-context"
preload={preload}
data-testid="via-loader-with-context"
>
via-loader-with-context
</Link>
</div>
</div>
)
},
Expand Down
23 changes: 23 additions & 0 deletions e2e/react-start/basic/src/routes/not-found/via-head.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createFileRoute, notFound } from '@tanstack/react-router'

export const Route = createFileRoute('/not-found/via-head')({
head: () => {
throw notFound()
},
component: RouteComponent,
notFoundComponent: () => {
return (
<div data-testid="via-head-notFound-component">
Not Found "/not-found/via-head"!
</div>
)
},
})

function RouteComponent() {
return (
<div data-testid="via-head-route-component" data-server={typeof window}>
Hello "/not-found/via-head"!
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createFileRoute, notFound, useRouteContext } from '@tanstack/react-router'

export const Route = createFileRoute('/not-found/via-loader-with-context')({
beforeLoad: () => {
return {
fool: 'of a Took'
}
},
loader: () => {
throw notFound()
},
component: RouteComponent,
notFoundComponent: () => {
const context = useRouteContext({ strict: false })
return (
<div data-testid="via-loader-with-context-notFound-component" data-server={typeof window}>
{`Hello you fool ${context.fool}`}
</div>
)
},
})

function RouteComponent() {
return (
<div data-testid="via-loader-with-context-route-component" data-server={typeof window}>
Hello "/not-found/via-loader-with-context"!
</div>
)
}
8 changes: 3 additions & 5 deletions e2e/react-start/basic/tests/not-found.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const combinate = (combinateImport as any).default as typeof combinateImport
test.use({
whitelistErrors: [
/Failed to load resource: the server responded with a status of 404/,
'Error during route context hydration: {isNotFound: true}',
],
})
test.describe('not-found', () => {
Expand All @@ -24,8 +25,7 @@ test.describe('not-found', () => {

test.describe('throw notFound()', () => {
const navigationTestMatrix = combinate({
// TODO beforeLoad!
thrower: [/* 'beforeLoad',*/ 'loader'] as const,
thrower: ['beforeLoad', 'head', 'loader', 'loader-with-context'] as const,
preload: [false, true] as const,
})

Expand Down Expand Up @@ -55,9 +55,7 @@ test.describe('not-found', () => {
})
})
const directVisitTestMatrix = combinate({
// TODO beforeLoad!

thrower: [/* 'beforeLoad',*/ 'loader'] as const,
thrower: ['beforeLoad', 'head', 'loader', 'loader-with-context'] as const,
})

directVisitTestMatrix.forEach(({ thrower }) => {
Expand Down
2 changes: 2 additions & 0 deletions e2e/react-start/basic/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ const prerenderConfiguration = {
'/redirect',
'/i-do-not-exist',
'/not-found/via-beforeLoad',
'/not-found/via-head',
'/not-found/via-loader',
'/not-found/via-loader-with-context',
].some((p) => page.path.includes(p)),
maxRedirects: 100,
}
Expand Down
43 changes: 43 additions & 0 deletions e2e/solid-start/basic/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import { Route as SearchParamsLoaderThrowsRedirectRouteImport } from './routes/s
import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/default'
import { Route as RedirectTargetRouteImport } from './routes/redirect/$target'
import { Route as PostsPostIdRouteImport } from './routes/posts.$postId'
import { Route as NotFoundViaLoaderWithContextRouteImport } from './routes/not-found/via-loader-with-context'
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 ApiUsersRouteImport } from './routes/api/users'
import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2'
Expand Down Expand Up @@ -158,11 +160,22 @@ const PostsPostIdRoute = PostsPostIdRouteImport.update({
path: '/$postId',
getParentRoute: () => PostsRoute,
} as any)
const NotFoundViaLoaderWithContextRoute =
NotFoundViaLoaderWithContextRouteImport.update({
id: '/via-loader-with-context',
path: '/via-loader-with-context',
getParentRoute: () => NotFoundRouteRoute,
} as any)
const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({
id: '/via-loader',
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',
Expand Down Expand Up @@ -252,7 +265,9 @@ export interface FileRoutesByFullPath {
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
'/api/users': typeof ApiUsersRouteWithChildren
'/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute
'/not-found/via-head': typeof NotFoundViaHeadRoute
'/not-found/via-loader': typeof NotFoundViaLoaderRoute
'/not-found/via-loader-with-context': typeof NotFoundViaLoaderWithContextRoute
'/posts/$postId': typeof PostsPostIdRoute
'/redirect/$target': typeof RedirectTargetRouteWithChildren
'/search-params/default': typeof SearchParamsDefaultRoute
Expand Down Expand Up @@ -285,7 +300,9 @@ export interface FileRoutesByTo {
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
'/api/users': typeof ApiUsersRouteWithChildren
'/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute
'/not-found/via-head': typeof NotFoundViaHeadRoute
'/not-found/via-loader': typeof NotFoundViaLoaderRoute
'/not-found/via-loader-with-context': typeof NotFoundViaLoaderWithContextRoute
'/posts/$postId': typeof PostsPostIdRoute
'/search-params/default': typeof SearchParamsDefaultRoute
'/search-params/loader-throws-redirect': typeof SearchParamsLoaderThrowsRedirectRoute
Expand Down Expand Up @@ -324,7 +341,9 @@ export interface FileRoutesById {
'/_layout/_layout-2': typeof LayoutLayout2RouteWithChildren
'/api/users': typeof ApiUsersRouteWithChildren
'/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute
'/not-found/via-head': typeof NotFoundViaHeadRoute
'/not-found/via-loader': typeof NotFoundViaLoaderRoute
'/not-found/via-loader-with-context': typeof NotFoundViaLoaderWithContextRoute
'/posts/$postId': typeof PostsPostIdRoute
'/redirect/$target': typeof RedirectTargetRouteWithChildren
'/search-params/default': typeof SearchParamsDefaultRoute
Expand Down Expand Up @@ -363,7 +382,9 @@ export interface FileRouteTypes {
| '/대한민국'
| '/api/users'
| '/not-found/via-beforeLoad'
| '/not-found/via-head'
| '/not-found/via-loader'
| '/not-found/via-loader-with-context'
| '/posts/$postId'
| '/redirect/$target'
| '/search-params/default'
Expand Down Expand Up @@ -396,7 +417,9 @@ export interface FileRouteTypes {
| '/대한민국'
| '/api/users'
| '/not-found/via-beforeLoad'
| '/not-found/via-head'
| '/not-found/via-loader'
| '/not-found/via-loader-with-context'
| '/posts/$postId'
| '/search-params/default'
| '/search-params/loader-throws-redirect'
Expand Down Expand Up @@ -434,7 +457,9 @@ export interface FileRouteTypes {
| '/_layout/_layout-2'
| '/api/users'
| '/not-found/via-beforeLoad'
| '/not-found/via-head'
| '/not-found/via-loader'
| '/not-found/via-loader-with-context'
| '/posts/$postId'
| '/redirect/$target'
| '/search-params/default'
Expand Down Expand Up @@ -633,13 +658,27 @@ declare module '@tanstack/solid-router' {
preLoaderRoute: typeof PostsPostIdRouteImport
parentRoute: typeof PostsRoute
}
'/not-found/via-loader-with-context': {
id: '/not-found/via-loader-with-context'
path: '/via-loader-with-context'
fullPath: '/not-found/via-loader-with-context'
preLoaderRoute: typeof NotFoundViaLoaderWithContextRouteImport
parentRoute: typeof NotFoundRouteRoute
}
'/not-found/via-loader': {
id: '/not-found/via-loader'
path: '/via-loader'
fullPath: '/not-found/via-loader'
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'
Expand Down Expand Up @@ -743,13 +782,17 @@ declare module '@tanstack/solid-router' {

interface NotFoundRouteRouteChildren {
NotFoundViaBeforeLoadRoute: typeof NotFoundViaBeforeLoadRoute
NotFoundViaHeadRoute: typeof NotFoundViaHeadRoute
NotFoundViaLoaderRoute: typeof NotFoundViaLoaderRoute
NotFoundViaLoaderWithContextRoute: typeof NotFoundViaLoaderWithContextRoute
NotFoundIndexRoute: typeof NotFoundIndexRoute
}

const NotFoundRouteRouteChildren: NotFoundRouteRouteChildren = {
NotFoundViaBeforeLoadRoute: NotFoundViaBeforeLoadRoute,
NotFoundViaHeadRoute: NotFoundViaHeadRoute,
NotFoundViaLoaderRoute: NotFoundViaLoaderRoute,
NotFoundViaLoaderWithContextRoute: NotFoundViaLoaderWithContextRoute,
NotFoundIndexRoute: NotFoundIndexRoute,
}

Expand Down
Loading