Skip to content

Commit 16a359b

Browse files
fix: don't create virtual routes for pathless layouts (#6120)
1 parent bffccb0 commit 16a359b

File tree

18 files changed

+403
-484
lines changed

18 files changed

+403
-484
lines changed

e2e/react-router/basic-file-based/src/routeTree.gen.ts

Lines changed: 101 additions & 0 deletions
Large diffs are not rendered by default.

e2e/react-router/basic-file-based/src/routes/__root.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,15 @@ function RootComponent() {
155155
}}
156156
>
157157
Masks
158+
</Link>{' '}
159+
<Link
160+
to="/pathless-layout"
161+
data-testid="link-to-pathless-layout"
162+
activeProps={{
163+
className: 'font-bold',
164+
}}
165+
>
166+
Pathless Layout
158167
</Link>
159168
</div>
160169
<hr />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/pathless-layout/_layout/child')({
4+
component: () => (
5+
<div data-testid="pathless-layout-child">Pathless Layout Child Route</div>
6+
),
7+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/pathless-layout/_layout/')({
4+
component: () => (
5+
<div data-testid="pathless-layout-index">Pathless Layout Index</div>
6+
),
7+
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/pathless-layout/_layout')({
4+
component: () => (
5+
<div>
6+
<div data-testid="pathless-layout-wrapper">Pathless Layout Wrapper</div>
7+
<nav>
8+
<Link to="/pathless-layout/child" data-testid="link-to-child">
9+
Go to Child
10+
</Link>
11+
</nav>
12+
<Outlet />
13+
</div>
14+
),
15+
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Outlet, createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/pathless-layout')({
4+
component: () => (
5+
<div>
6+
<h2 data-testid="pathless-layout-header">Pathless Layout Section</h2>
7+
<Outlet />
8+
</div>
9+
),
10+
notFoundComponent: () => (
11+
<div data-testid="pathless-layout-not-found">
12+
Not Found in Pathless Layout
13+
</div>
14+
),
15+
})

e2e/react-router/basic-file-based/tests/app.spec.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,70 @@ test.describe('Unicode route rendering', () => {
326326
expect(page.url()).toBe(`${baseURL}/%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD`)
327327
})
328328
})
329+
330+
test.describe('Pathless layout routes', () => {
331+
test('direct navigation to pathless layout route renders correctly', async ({
332+
page,
333+
}) => {
334+
await page.goto('/pathless-layout')
335+
await expect(page.getByTestId('pathless-layout-header')).toContainText(
336+
'Pathless Layout Section',
337+
)
338+
await expect(page.getByTestId('pathless-layout-wrapper')).toContainText(
339+
'Pathless Layout Wrapper',
340+
)
341+
await expect(page.getByTestId('pathless-layout-index')).toContainText(
342+
'Pathless Layout Index',
343+
)
344+
})
345+
346+
test('client-side navigation to pathless layout route', async ({ page }) => {
347+
await page.goto('/')
348+
await page.getByTestId('link-to-pathless-layout').click()
349+
await expect(page.getByTestId('pathless-layout-header')).toContainText(
350+
'Pathless Layout Section',
351+
)
352+
await expect(page.getByTestId('pathless-layout-wrapper')).toContainText(
353+
'Pathless Layout Wrapper',
354+
)
355+
})
356+
357+
test('navigation within pathless layout preserves layout', async ({
358+
page,
359+
}) => {
360+
await page.goto('/pathless-layout')
361+
await page.getByTestId('link-to-child').click()
362+
await expect(page.getByTestId('pathless-layout-header')).toContainText(
363+
'Pathless Layout Section',
364+
)
365+
await expect(page.getByTestId('pathless-layout-wrapper')).toContainText(
366+
'Pathless Layout Wrapper',
367+
)
368+
await expect(page.getByTestId('pathless-layout-child')).toContainText(
369+
'Pathless Layout Child Route',
370+
)
371+
})
372+
373+
test('direct navigation to child of pathless layout', async ({ page }) => {
374+
await page.goto('/pathless-layout/child')
375+
await expect(page.getByTestId('pathless-layout-header')).toContainText(
376+
'Pathless Layout Section',
377+
)
378+
await expect(page.getByTestId('pathless-layout-wrapper')).toContainText(
379+
'Pathless Layout Wrapper',
380+
)
381+
await expect(page.getByTestId('pathless-layout-child')).toContainText(
382+
'Pathless Layout Child Route',
383+
)
384+
})
385+
386+
test('navigating to non-existent route under pathless layout shows not found', async ({
387+
page,
388+
}) => {
389+
await page.goto('/pathless-layout/does-not-exist')
390+
await expect(page.getByTestId('pathless-layout-not-found')).toContainText(
391+
'Not Found in Pathless Layout',
392+
)
393+
await expect(page.locator('body')).toContainText('Not Found')
394+
})
395+
})

e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { Route as IndexRouteImport } from './routes/index'
1515
import { Route as PostsIndexRouteImport } from './routes/posts.index'
1616
import { Route as PostsPostIdRouteImport } from './routes/posts.$postId'
1717
import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2'
18-
import { Route as TransitionCountQueryRouteImport } from './routes/transition/count/query'
1918
import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b'
2019
import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a'
2120

@@ -47,11 +46,6 @@ const LayoutLayout2Route = LayoutLayout2RouteImport.update({
4746
id: '/_layout-2',
4847
getParentRoute: () => LayoutRoute,
4948
} as any)
50-
const TransitionCountQueryRoute = TransitionCountQueryRouteImport.update({
51-
id: '/transition/count/query',
52-
path: '/transition/count/query',
53-
getParentRoute: () => rootRouteImport,
54-
} as any)
5549
const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({
5650
id: '/layout-b',
5751
path: '/layout-b',
@@ -70,15 +64,13 @@ export interface FileRoutesByFullPath {
7064
'/posts/': typeof PostsIndexRoute
7165
'/layout-a': typeof LayoutLayout2LayoutARoute
7266
'/layout-b': typeof LayoutLayout2LayoutBRoute
73-
'/transition/count/query': typeof TransitionCountQueryRoute
7467
}
7568
export interface FileRoutesByTo {
7669
'/': typeof IndexRoute
7770
'/posts/$postId': typeof PostsPostIdRoute
7871
'/posts': typeof PostsIndexRoute
7972
'/layout-a': typeof LayoutLayout2LayoutARoute
8073
'/layout-b': typeof LayoutLayout2LayoutBRoute
81-
'/transition/count/query': typeof TransitionCountQueryRoute
8274
}
8375
export interface FileRoutesById {
8476
__root__: typeof rootRouteImport
@@ -90,7 +82,6 @@ export interface FileRoutesById {
9082
'/posts/': typeof PostsIndexRoute
9183
'/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute
9284
'/_layout/_layout-2/layout-b': typeof LayoutLayout2LayoutBRoute
93-
'/transition/count/query': typeof TransitionCountQueryRoute
9485
}
9586
export interface FileRouteTypes {
9687
fileRoutesByFullPath: FileRoutesByFullPath
@@ -101,15 +92,8 @@ export interface FileRouteTypes {
10192
| '/posts/'
10293
| '/layout-a'
10394
| '/layout-b'
104-
| '/transition/count/query'
10595
fileRoutesByTo: FileRoutesByTo
106-
to:
107-
| '/'
108-
| '/posts/$postId'
109-
| '/posts'
110-
| '/layout-a'
111-
| '/layout-b'
112-
| '/transition/count/query'
96+
to: '/' | '/posts/$postId' | '/posts' | '/layout-a' | '/layout-b'
11397
id:
11498
| '__root__'
11599
| '/'
@@ -120,14 +104,12 @@ export interface FileRouteTypes {
120104
| '/posts/'
121105
| '/_layout/_layout-2/layout-a'
122106
| '/_layout/_layout-2/layout-b'
123-
| '/transition/count/query'
124107
fileRoutesById: FileRoutesById
125108
}
126109
export interface RootRouteChildren {
127110
IndexRoute: typeof IndexRoute
128111
LayoutRoute: typeof LayoutRouteWithChildren
129112
PostsRoute: typeof PostsRouteWithChildren
130-
TransitionCountQueryRoute: typeof TransitionCountQueryRoute
131113
}
132114

133115
declare module '@tanstack/react-router' {
@@ -174,13 +156,6 @@ declare module '@tanstack/react-router' {
174156
preLoaderRoute: typeof LayoutLayout2RouteImport
175157
parentRoute: typeof LayoutRoute
176158
}
177-
'/transition/count/query': {
178-
id: '/transition/count/query'
179-
path: '/transition/count/query'
180-
fullPath: '/transition/count/query'
181-
preLoaderRoute: typeof TransitionCountQueryRouteImport
182-
parentRoute: typeof rootRouteImport
183-
}
184159
'/_layout/_layout-2/layout-b': {
185160
id: '/_layout/_layout-2/layout-b'
186161
path: '/layout-b'
@@ -239,7 +214,6 @@ const rootRouteChildren: RootRouteChildren = {
239214
IndexRoute: IndexRoute,
240215
LayoutRoute: LayoutRouteWithChildren,
241216
PostsRoute: PostsRouteWithChildren,
242-
TransitionCountQueryRoute: TransitionCountQueryRoute,
243217
}
244218
export const routeTree = rootRouteImport
245219
._addFileChildren(rootRouteChildren)

e2e/react-start/basic/src/routeTree.gen.ts

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// You should NOT make any changes in this file as it will be overwritten.
99
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
1010

11-
import { createFileRoute } from '@tanstack/react-router'
12-
1311
import { Route as rootRouteImport } from './routes/__root'
1412
import { Route as Char45824Char54620Char48124Char44397RouteImport } from './routes/대한민국'
1513
import { Route as UsersRouteImport } from './routes/users'
@@ -54,8 +52,6 @@ import { Route as RedirectTargetServerFnViaBeforeLoadRouteImport } from './route
5452
import { Route as FooBarQuxHereRouteImport } from './routes/foo/$bar/$qux/_here'
5553
import { Route as FooBarQuxHereIndexRouteImport } from './routes/foo/$bar/$qux/_here/index'
5654

57-
const FooBarQuxRouteImport = createFileRoute('/foo/$bar/$qux')()
58-
5955
const Char45824Char54620Char48124Char44397Route =
6056
Char45824Char54620Char48124Char44397RouteImport.update({
6157
id: '/대한민국',
@@ -203,11 +199,6 @@ const LayoutLayout2Route = LayoutLayout2RouteImport.update({
203199
id: '/_layout-2',
204200
getParentRoute: () => LayoutRoute,
205201
} as any)
206-
const FooBarQuxRoute = FooBarQuxRouteImport.update({
207-
id: '/foo/$bar/$qux',
208-
path: '/foo/$bar/$qux',
209-
getParentRoute: () => rootRouteImport,
210-
} as any)
211202
const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({
212203
id: '/',
213204
path: '/',
@@ -269,8 +260,9 @@ const RedirectTargetServerFnViaBeforeLoadRoute =
269260
getParentRoute: () => RedirectTargetRoute,
270261
} as any)
271262
const FooBarQuxHereRoute = FooBarQuxHereRouteImport.update({
272-
id: '/_here',
273-
getParentRoute: () => FooBarQuxRoute,
263+
id: '/foo/$bar/$qux/_here',
264+
path: '/foo/$bar/$qux',
265+
getParentRoute: () => rootRouteImport,
274266
} as any)
275267
const FooBarQuxHereIndexRoute = FooBarQuxHereIndexRouteImport.update({
276268
id: '/',
@@ -350,11 +342,11 @@ export interface FileRoutesByTo {
350342
'/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute
351343
'/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute
352344
'/redirect/$target': typeof RedirectTargetIndexRoute
353-
'/foo/$bar/$qux': typeof FooBarQuxHereIndexRoute
354345
'/redirect/$target/serverFn/via-beforeLoad': typeof RedirectTargetServerFnViaBeforeLoadRoute
355346
'/redirect/$target/serverFn/via-loader': typeof RedirectTargetServerFnViaLoaderRoute
356347
'/redirect/$target/serverFn/via-useServerFn': typeof RedirectTargetServerFnViaUseServerFnRoute
357348
'/redirect/$target/serverFn': typeof RedirectTargetServerFnIndexRoute
349+
'/foo/$bar/$qux': typeof FooBarQuxHereIndexRoute
358350
}
359351
export interface FileRoutesById {
360352
__root__: typeof rootRouteImport
@@ -394,7 +386,6 @@ export interface FileRoutesById {
394386
'/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute
395387
'/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute
396388
'/redirect/$target/': typeof RedirectTargetIndexRoute
397-
'/foo/$bar/$qux': typeof FooBarQuxRouteWithChildren
398389
'/foo/$bar/$qux/_here': typeof FooBarQuxHereRouteWithChildren
399390
'/redirect/$target/serverFn/via-beforeLoad': typeof RedirectTargetServerFnViaBeforeLoadRoute
400391
'/redirect/$target/serverFn/via-loader': typeof RedirectTargetServerFnViaLoaderRoute
@@ -476,11 +467,11 @@ export interface FileRouteTypes {
476467
| '/redirect/$target/via-beforeLoad'
477468
| '/redirect/$target/via-loader'
478469
| '/redirect/$target'
479-
| '/foo/$bar/$qux'
480470
| '/redirect/$target/serverFn/via-beforeLoad'
481471
| '/redirect/$target/serverFn/via-loader'
482472
| '/redirect/$target/serverFn/via-useServerFn'
483473
| '/redirect/$target/serverFn'
474+
| '/foo/$bar/$qux'
484475
id:
485476
| '__root__'
486477
| '/'
@@ -519,7 +510,6 @@ export interface FileRouteTypes {
519510
| '/redirect/$target/via-beforeLoad'
520511
| '/redirect/$target/via-loader'
521512
| '/redirect/$target/'
522-
| '/foo/$bar/$qux'
523513
| '/foo/$bar/$qux/_here'
524514
| '/redirect/$target/serverFn/via-beforeLoad'
525515
| '/redirect/$target/serverFn/via-loader'
@@ -547,7 +537,7 @@ export interface RootRouteChildren {
547537
MultiCookieRedirectIndexRoute: typeof MultiCookieRedirectIndexRoute
548538
RedirectIndexRoute: typeof RedirectIndexRoute
549539
PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute
550-
FooBarQuxRoute: typeof FooBarQuxRouteWithChildren
540+
FooBarQuxHereRoute: typeof FooBarQuxHereRouteWithChildren
551541
}
552542

553543
declare module '@tanstack/react-router' {
@@ -755,13 +745,6 @@ declare module '@tanstack/react-router' {
755745
preLoaderRoute: typeof LayoutLayout2RouteImport
756746
parentRoute: typeof LayoutRoute
757747
}
758-
'/foo/$bar/$qux': {
759-
id: '/foo/$bar/$qux'
760-
path: '/foo/$bar/$qux'
761-
fullPath: '/foo/$bar/$qux'
762-
preLoaderRoute: typeof FooBarQuxRouteImport
763-
parentRoute: typeof rootRouteImport
764-
}
765748
'/redirect/$target/': {
766749
id: '/redirect/$target/'
767750
path: '/'
@@ -844,7 +827,7 @@ declare module '@tanstack/react-router' {
844827
path: '/foo/$bar/$qux'
845828
fullPath: '/foo/$bar/$qux'
846829
preLoaderRoute: typeof FooBarQuxHereRouteImport
847-
parentRoute: typeof FooBarQuxRoute
830+
parentRoute: typeof rootRouteImport
848831
}
849832
'/foo/$bar/$qux/_here/': {
850833
id: '/foo/$bar/$qux/_here/'
@@ -988,18 +971,6 @@ const FooBarQuxHereRouteWithChildren = FooBarQuxHereRoute._addFileChildren(
988971
FooBarQuxHereRouteChildren,
989972
)
990973

991-
interface FooBarQuxRouteChildren {
992-
FooBarQuxHereRoute: typeof FooBarQuxHereRouteWithChildren
993-
}
994-
995-
const FooBarQuxRouteChildren: FooBarQuxRouteChildren = {
996-
FooBarQuxHereRoute: FooBarQuxHereRouteWithChildren,
997-
}
998-
999-
const FooBarQuxRouteWithChildren = FooBarQuxRoute._addFileChildren(
1000-
FooBarQuxRouteChildren,
1001-
)
1002-
1003974
const rootRouteChildren: RootRouteChildren = {
1004975
IndexRoute: IndexRoute,
1005976
NotFoundRouteRoute: NotFoundRouteRouteWithChildren,
@@ -1020,7 +991,7 @@ const rootRouteChildren: RootRouteChildren = {
1020991
MultiCookieRedirectIndexRoute: MultiCookieRedirectIndexRoute,
1021992
RedirectIndexRoute: RedirectIndexRoute,
1022993
PostsPostIdDeepRoute: PostsPostIdDeepRoute,
1023-
FooBarQuxRoute: FooBarQuxRouteWithChildren,
994+
FooBarQuxHereRoute: FooBarQuxHereRouteWithChildren,
1024995
}
1025996
export const routeTree = rootRouteImport
1026997
._addFileChildren(rootRouteChildren)

0 commit comments

Comments
 (0)