Skip to content

Commit 67c56ba

Browse files
fix(router-generator): fix parent resolution logic
fixes #6261
1 parent 17045eb commit 67c56ba

6 files changed

Lines changed: 166 additions & 12 deletions

File tree

packages/router-generator/src/generator.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,19 +1422,33 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved
14221422
) {
14231423
let parentRoute = hasParentRoute(prefixMap, node, node.routePath)
14241424

1425-
// Fallback: check acc.routeNodesByPath for parents not in prefixMap
1426-
// This handles virtual routes created from lazy-only files that weren't
1427-
// in the initial prefixMap build
1428-
if (!parentRoute && node.routePath) {
1429-
let searchPath = node.routePath
1430-
while (searchPath.length > 0) {
1431-
const lastSlash = searchPath.lastIndexOf('/')
1432-
if (lastSlash <= 0) break
1433-
searchPath = searchPath.substring(0, lastSlash)
1434-
const candidate = acc.routeNodesByPath.get(searchPath)
1435-
if (candidate && candidate.routePath !== node.routePath) {
1425+
// Check routeNodesByPath for a closer parent that may not be in prefixMap.
1426+
//
1427+
// Why: The prefixMap excludes lazy routes by design. When lazy-only routes are
1428+
// nested inside a pathless layout, the virtual route created from the lazy file
1429+
// won't be in the prefixMap, but it will be in routeNodesByPath.
1430+
//
1431+
// Example: Given files _layout/path.lazy.tsx and _layout/path.index.lazy.tsx:
1432+
// - prefixMap contains: /_layout (from route.tsx)
1433+
// - routeNodesByPath contains: /_layout AND /_layout/path (virtual from lazy)
1434+
// - For /_layout/path/, hasParentRoute returns /_layout (wrong)
1435+
// - But the correct parent is /_layout/path (the virtual route from path.lazy.tsx)
1436+
//
1437+
// Optimization: Only search if we might find a closer parent. The search walks
1438+
// up from the immediate parent path, so if the first candidate matches what
1439+
// prefixMap found, there's no closer parent to find.
1440+
if (node.routePath) {
1441+
const lastSlash = node.routePath.lastIndexOf('/')
1442+
if (lastSlash > 0) {
1443+
const immediateParentPath = node.routePath.substring(0, lastSlash)
1444+
const candidate = acc.routeNodesByPath.get(immediateParentPath)
1445+
if (
1446+
candidate &&
1447+
candidate.routePath !== node.routePath &&
1448+
candidate !== parentRoute
1449+
) {
1450+
// Found a closer parent in routeNodesByPath that differs from prefixMap result
14361451
parentRoute = candidate
1437-
break
14381452
}
14391453
}
14401454
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* eslint-disable */
2+
3+
// @ts-nocheck
4+
5+
// noinspection JSUnusedGlobalSymbols
6+
7+
// This file was automatically generated by TanStack Router.
8+
// You should NOT make any changes in this file as it will be overwritten.
9+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10+
11+
import { createFileRoute } from '@tanstack/react-router'
12+
13+
import { Route as rootRouteImport } from './routes/__root'
14+
import { Route as LayoutRouteRouteImport } from './routes/_layout/route'
15+
16+
const LayoutPathLazyRouteImport = createFileRoute('/_layout/path')()
17+
const LayoutPathIndexLazyRouteImport = createFileRoute('/_layout/path/')()
18+
19+
const LayoutRouteRoute = LayoutRouteRouteImport.update({
20+
id: '/_layout',
21+
getParentRoute: () => rootRouteImport,
22+
} as any)
23+
const LayoutPathLazyRoute = LayoutPathLazyRouteImport.update({
24+
id: '/path',
25+
path: '/path',
26+
getParentRoute: () => LayoutRouteRoute,
27+
} as any).lazy(() => import('./routes/_layout/path.lazy').then((d) => d.Route))
28+
const LayoutPathIndexLazyRoute = LayoutPathIndexLazyRouteImport.update({
29+
id: '/',
30+
path: '/',
31+
getParentRoute: () => LayoutPathLazyRoute,
32+
} as any).lazy(() =>
33+
import('./routes/_layout/path.index.lazy').then((d) => d.Route),
34+
)
35+
36+
export interface FileRoutesByFullPath {
37+
'/': typeof LayoutRouteRouteWithChildren
38+
'/path': typeof LayoutPathLazyRouteWithChildren
39+
'/path/': typeof LayoutPathIndexLazyRoute
40+
}
41+
export interface FileRoutesByTo {
42+
'/': typeof LayoutRouteRouteWithChildren
43+
'/path': typeof LayoutPathIndexLazyRoute
44+
}
45+
export interface FileRoutesById {
46+
__root__: typeof rootRouteImport
47+
'/_layout': typeof LayoutRouteRouteWithChildren
48+
'/_layout/path': typeof LayoutPathLazyRouteWithChildren
49+
'/_layout/path/': typeof LayoutPathIndexLazyRoute
50+
}
51+
export interface FileRouteTypes {
52+
fileRoutesByFullPath: FileRoutesByFullPath
53+
fullPaths: '/' | '/path' | '/path/'
54+
fileRoutesByTo: FileRoutesByTo
55+
to: '/' | '/path'
56+
id: '__root__' | '/_layout' | '/_layout/path' | '/_layout/path/'
57+
fileRoutesById: FileRoutesById
58+
}
59+
export interface RootRouteChildren {
60+
LayoutRouteRoute: typeof LayoutRouteRouteWithChildren
61+
}
62+
63+
declare module '@tanstack/react-router' {
64+
interface FileRoutesByPath {
65+
'/_layout': {
66+
id: '/_layout'
67+
path: ''
68+
fullPath: '/'
69+
preLoaderRoute: typeof LayoutRouteRouteImport
70+
parentRoute: typeof rootRouteImport
71+
}
72+
'/_layout/path': {
73+
id: '/_layout/path'
74+
path: '/path'
75+
fullPath: '/path'
76+
preLoaderRoute: typeof LayoutPathLazyRouteImport
77+
parentRoute: typeof LayoutRouteRoute
78+
}
79+
'/_layout/path/': {
80+
id: '/_layout/path/'
81+
path: '/'
82+
fullPath: '/path/'
83+
preLoaderRoute: typeof LayoutPathIndexLazyRouteImport
84+
parentRoute: typeof LayoutPathLazyRoute
85+
}
86+
}
87+
}
88+
89+
interface LayoutPathLazyRouteChildren {
90+
LayoutPathIndexLazyRoute: typeof LayoutPathIndexLazyRoute
91+
}
92+
93+
const LayoutPathLazyRouteChildren: LayoutPathLazyRouteChildren = {
94+
LayoutPathIndexLazyRoute: LayoutPathIndexLazyRoute,
95+
}
96+
97+
const LayoutPathLazyRouteWithChildren = LayoutPathLazyRoute._addFileChildren(
98+
LayoutPathLazyRouteChildren,
99+
)
100+
101+
interface LayoutRouteRouteChildren {
102+
LayoutPathLazyRoute: typeof LayoutPathLazyRouteWithChildren
103+
}
104+
105+
const LayoutRouteRouteChildren: LayoutRouteRouteChildren = {
106+
LayoutPathLazyRoute: LayoutPathLazyRouteWithChildren,
107+
}
108+
109+
const LayoutRouteRouteWithChildren = LayoutRouteRoute._addFileChildren(
110+
LayoutRouteRouteChildren,
111+
)
112+
113+
const rootRouteChildren: RootRouteChildren = {
114+
LayoutRouteRoute: LayoutRouteRouteWithChildren,
115+
}
116+
export const routeTree = rootRouteImport
117+
._addFileChildren(rootRouteChildren)
118+
._addFileTypes<FileRouteTypes>()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createRootRoute } from '@tanstack/react-router'
2+
3+
export const Route = createRootRoute()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { createLazyFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createLazyFileRoute('/_layout/path/')({
4+
component: () => 'Path Index',
5+
})
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { createLazyFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createLazyFileRoute('/_layout/path')({
4+
component: () => 'Path Layout',
5+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Outlet, createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/_layout')({
4+
component: RouteComponent,
5+
})
6+
7+
function RouteComponent() {
8+
return <Outlet />
9+
}

0 commit comments

Comments
 (0)