From 92e28461f9b1e24d55efd8ef8716d94570e9d908 Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Wed, 17 Dec 2025 02:41:35 +0100 Subject: [PATCH 1/4] fix: don't create virtual routes for pathless layouts fixes #3843 --- packages/router-generator/src/generator.ts | 123 ++++++------------ packages/router-generator/src/types.ts | 3 +- packages/router-generator/src/utils.ts | 6 +- .../routeTree.nonnested.snapshot.ts | 107 ++++----------- .../nested-layouts/routeTree.snapshot.ts | 107 ++++----------- .../routeTree.nonnested.snapshot.ts | 38 +----- .../routeTree.snapshot.ts | 38 +----- .../routeTree.nonnested.snapshot.ts | 86 +++++------- .../route-groups/routeTree.snapshot.ts | 86 +++++------- 9 files changed, 172 insertions(+), 422 deletions(-) diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index baf9dd89a2e..afe05345b51 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -38,7 +38,6 @@ import { removeUnderscores, replaceBackslash, resetRegex, - routePathToVariable, trimPathLeft, } from './utils' import { fillTemplate, getTargetTemplate } from './template' @@ -409,6 +408,7 @@ export class Generator { routeTree: [], routeNodes: [], routePiecesByPath: {}, + routeNodesByPath: new Map(), } for (const node of routeFileResult) { @@ -651,7 +651,10 @@ export class Generator { `const ${node.variableName}Route = ${node.variableName}RouteImport.update({ ${[ `id: '${node.path}'`, - !node.isNonPath ? `path: '${node.cleanedPath}'` : undefined, + !node.isNonPath || + (node._fsRouteType === 'pathless_layout' && node.cleanedPath) + ? `path: '${node.cleanedPath}'` + : undefined, `getParentRoute: () => ${findParent(node)}`, ] .filter(Boolean) @@ -1351,27 +1354,13 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved resetRegex(this.routeGroupPatternRegex) - let parentRoute = hasParentRoute( + const parentRoute = hasParentRoute( acc.routeNodes, node, node.routePath, node.originalRoutePath, ) - // if the parent route is a virtual parent route, we need to find the real parent route - if (parentRoute?.isVirtualParentRoute && parentRoute.children?.length) { - // only if this sub-parent route returns a valid parent route, we use it, if not leave it as it - const possibleParentRoute = hasParentRoute( - parentRoute.children, - node, - node.routePath, - node.originalRoutePath, - ) - if (possibleParentRoute) { - parentRoute = possibleParentRoute - } - } - if (parentRoute) node.parent = parentRoute node.path = determineNodePath(node) @@ -1419,23 +1408,11 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved acc.routePiecesByPath[node.routePath!] = acc.routePiecesByPath[node.routePath!] || {} - acc.routePiecesByPath[node.routePath!]![ - node._fsRouteType === 'lazy' - ? 'lazy' - : node._fsRouteType === 'loader' - ? 'loader' - : node._fsRouteType === 'errorComponent' - ? 'errorComponent' - : node._fsRouteType === 'notFoundComponent' - ? 'notFoundComponent' - : node._fsRouteType === 'pendingComponent' - ? 'pendingComponent' - : 'component' - ] = node - - const anchorRoute = acc.routeNodes.find( - (d) => d.routePath === node.routePath, - ) + const pieceKey = + node._fsRouteType === 'lazy' ? 'lazy' : (node._fsRouteType as keyof typeof acc.routePiecesByPath[string]) + acc.routePiecesByPath[node.routePath!]![pieceKey] = node + + const anchorRoute = acc.routeNodesByPath.get(node.routePath!) // Don't create virtual routes for root route component pieces - the root route is handled separately if (!anchorRoute && node.routePath !== `/${rootPathId}`) { @@ -1452,66 +1429,44 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved return } - const cleanedPathIsEmpty = (node.cleanedPath || '').length === 0 - const nonPathRoute = - node._fsRouteType === 'pathless_layout' && node.isNonPath - - node.isVirtualParentRequired = - node._fsRouteType === 'pathless_layout' || nonPathRoute - ? !cleanedPathIsEmpty - : false - - if (!node.isVirtual && node.isVirtualParentRequired) { - const parentRoutePath = removeLastSegmentFromPath(node.routePath) || '/' - const parentVariableName = routePathToVariable(parentRoutePath) - - const anchorRoute = acc.routeNodes.find( - (d) => d.routePath === parentRoutePath, - ) - - if (!anchorRoute) { - const parentNode: RouteNode = { - ...node, - path: removeLastSegmentFromPath(node.path) || '/', - filePath: removeLastSegmentFromPath(node.filePath) || '/', - fullPath: removeLastSegmentFromPath(node.fullPath) || '/', - routePath: parentRoutePath, - variableName: parentVariableName, - isVirtual: true, - _fsRouteType: 'layout', // layout since this route will wrap other routes - isVirtualParentRoute: true, - isVirtualParentRequired: false, - } - - parentNode.children = parentNode.children ?? [] - parentNode.children.push(node) - - node.parent = parentNode - - if (node._fsRouteType === 'pathless_layout') { - // since `node.path` is used as the `id` on the route definition, we need to update it - node.path = determineNodePath(node) + const isPathlessLayoutWithPath = + node._fsRouteType === 'pathless_layout' && + node.cleanedPath && + node.cleanedPath.length > 0 + + // Special handling: pathless layouts with path need to find real ancestor + if (!node.isVirtual && isPathlessLayoutWithPath) { + const immediateParentPath = removeLastSegmentFromPath(node.routePath) || '/' + let searchPath = immediateParentPath + + // Find nearest real (non-virtual, non-index) parent + while (searchPath) { + const candidate = acc.routeNodesByPath.get(searchPath) + if (candidate && !candidate.isVirtual && candidate.path !== '/') { + node.parent = candidate + node.path = node.routePath + node.cleanedPath = removeGroups( + removeUnderscores(removeLayoutSegments(immediateParentPath)) ?? '', + ) + break } - - this.handleNode(parentNode, acc, config) - } else { - anchorRoute.children = anchorRoute.children ?? [] - anchorRoute.children.push(node) - - node.parent = anchorRoute + if (searchPath === '/') break + searchPath = removeLastSegmentFromPath(searchPath) || '/' } } + // Add to parent's children or to root if (node.parent) { - if (!node.isVirtualParentRequired) { - node.parent.children = node.parent.children ?? [] - node.parent.children.push(node) - } + node.parent.children = node.parent.children ?? [] + node.parent.children.push(node) } else { acc.routeTree.push(node) } acc.routeNodes.push(node) + if (node.routePath && !node.isVirtual) { + acc.routeNodesByPath.set(node.routePath, node) + } } // only process files that are relevant for the route tree generation diff --git a/packages/router-generator/src/types.ts b/packages/router-generator/src/types.ts index 997d5ff7a20..4c077581521 100644 --- a/packages/router-generator/src/types.ts +++ b/packages/router-generator/src/types.ts @@ -8,7 +8,6 @@ export type RouteNode = { cleanedPath?: string path?: string isNonPath?: boolean - isVirtualParentRequired?: boolean isVirtualParentRoute?: boolean isVirtual?: boolean children?: Array @@ -58,6 +57,8 @@ export type HandleNodeAccumulator = { routeTree: Array routePiecesByPath: Record routeNodes: Array + /** O(1) lookup by routePath - avoids O(n) .find() on every node */ + routeNodesByPath: Map } export type GetRoutesByFileMapResultValue = { routePath: string } diff --git a/packages/router-generator/src/utils.ts b/packages/router-generator/src/utils.ts index 5f497c85440..d1d579ed81f 100644 --- a/packages/router-generator/src/utils.ts +++ b/packages/router-generator/src/utils.ts @@ -711,11 +711,7 @@ export const findParent = (node: RouteNode | undefined): string => { return `rootRouteImport` } if (node.parent) { - if (node.isVirtualParentRequired) { - return `${node.parent.variableName}Route` - } else { - return `${node.parent.variableName}Route` - } + return `${node.parent.variableName}Route` } return findParent(node.parent) } diff --git a/packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts b/packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts index c76e88e21d9..6501b213ecc 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts +++ b/packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts @@ -8,8 +8,6 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { createFileRoute } from '@tanstack/react-router' - import { Route as rootRouteImport } from './routes/__root' import { Route as LayoutA2RouteImport } from './routes/_layout-a2' import { Route as LayoutA1RouteImport } from './routes/_layout-a1' @@ -35,19 +33,6 @@ import { Route as FooLayoutB5IdRouteImport } from './routes/foo/_layout-b5/$id' import { Route as NestedLayoutB1LayoutC1BarRouteImport } from './routes/nested/_layout-b1/_layout-c1/bar' import { Route as JestedLayoutB3LayoutC2BarRouteImport } from './routes/jested/_layout-b3/_layout-c2/bar' -const NestedRouteImport = createFileRoute('/nested')() -const FooRouteImport = createFileRoute('/foo')() - -const NestedRoute = NestedRouteImport.update({ - id: '/nested', - path: '/nested', - getParentRoute: () => rootRouteImport, -} as any) -const FooRoute = FooRouteImport.update({ - id: '/foo', - path: '/foo', - getParentRoute: () => rootRouteImport, -} as any) const LayoutA2Route = LayoutA2RouteImport.update({ id: '/_layout-a2', getParentRoute: () => rootRouteImport, @@ -67,12 +52,14 @@ const IndexRoute = IndexRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const NestedLayoutB2Route = NestedLayoutB2RouteImport.update({ - id: '/_layout-b2', - getParentRoute: () => NestedRoute, + id: '/nested/_layout-b2', + path: '/nested', + getParentRoute: () => rootRouteImport, } as any) const NestedLayoutB1Route = NestedLayoutB1RouteImport.update({ - id: '/_layout-b1', - getParentRoute: () => NestedRoute, + id: '/nested/_layout-b1', + path: '/nested', + getParentRoute: () => rootRouteImport, } as any) const JestedLayoutB4Route = JestedLayoutB4RouteImport.update({ id: '/_layout-b4', @@ -83,9 +70,9 @@ const JestedLayoutB3Route = JestedLayoutB3RouteImport.update({ getParentRoute: () => JestedRouteRoute, } as any) const FooBarRoute = FooBarRouteImport.update({ - id: '/bar', - path: '/bar', - getParentRoute: () => FooRoute, + id: '/foo/bar', + path: '/foo/bar', + getParentRoute: () => rootRouteImport, } as any) const LayoutA2BarRoute = LayoutA2BarRouteImport.update({ id: '/bar', @@ -103,8 +90,9 @@ const folderInFolderRoute = folderInFolderRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const FooLayoutB5RouteRoute = FooLayoutB5RouteRouteImport.update({ - id: '/_layout-b5', - getParentRoute: () => FooRoute, + id: '/foo/_layout-b5', + path: '/foo', + getParentRoute: () => rootRouteImport, } as any) const NestedLayoutB1IndexRoute = NestedLayoutB1IndexRouteImport.update({ id: '/', @@ -177,8 +165,8 @@ export interface FileRoutesByFullPath { export interface FileRoutesByTo { '/': typeof IndexRoute '/jested': typeof JestedLayoutB3IndexRoute - '/foo': typeof FooLayoutB5IndexRoute '/in-folder': typeof folderInFolderRoute + '/foo': typeof FooLayoutB5IndexRoute '/bar': typeof LayoutA2BarRoute '/foo/bar': typeof FooBarRoute '/nested': typeof NestedLayoutB1IndexRoute @@ -194,7 +182,6 @@ export interface FileRoutesById { '/jested': typeof JestedRouteRouteWithChildren '/_layout-a1': typeof LayoutA1RouteWithChildren '/_layout-a2': typeof LayoutA2RouteWithChildren - '/foo': typeof FooRouteWithChildren '/foo/_layout-b5': typeof FooLayoutB5RouteRouteWithChildren '/(folder)/in-folder': typeof folderInFolderRoute '/_layout-a1/foo': typeof LayoutA1FooRoute @@ -202,7 +189,6 @@ export interface FileRoutesById { '/foo/bar': typeof FooBarRoute '/jested/_layout-b3': typeof JestedLayoutB3RouteWithChildren '/jested/_layout-b4': typeof JestedLayoutB4RouteWithChildren - '/nested': typeof NestedRouteWithChildren '/nested/_layout-b1': typeof NestedLayoutB1RouteWithChildren '/nested/_layout-b2': typeof NestedLayoutB2RouteWithChildren '/foo/_layout-b5/$id': typeof FooLayoutB5IdRoute @@ -238,8 +224,8 @@ export interface FileRouteTypes { to: | '/' | '/jested' - | '/foo' | '/in-folder' + | '/foo' | '/bar' | '/foo/bar' | '/nested' @@ -254,7 +240,6 @@ export interface FileRouteTypes { | '/jested' | '/_layout-a1' | '/_layout-a2' - | '/foo' | '/foo/_layout-b5' | '/(folder)/in-folder' | '/_layout-a1/foo' @@ -262,7 +247,6 @@ export interface FileRouteTypes { | '/foo/bar' | '/jested/_layout-b3' | '/jested/_layout-b4' - | '/nested' | '/nested/_layout-b1' | '/nested/_layout-b2' | '/foo/_layout-b5/$id' @@ -282,27 +266,15 @@ export interface RootRouteChildren { JestedRouteRoute: typeof JestedRouteRouteWithChildren LayoutA1Route: typeof LayoutA1RouteWithChildren LayoutA2Route: typeof LayoutA2RouteWithChildren - FooRoute: typeof FooRouteWithChildren + FooLayoutB5RouteRoute: typeof FooLayoutB5RouteRouteWithChildren folderInFolderRoute: typeof folderInFolderRoute - NestedRoute: typeof NestedRouteWithChildren + FooBarRoute: typeof FooBarRoute + NestedLayoutB1Route: typeof NestedLayoutB1RouteWithChildren + NestedLayoutB2Route: typeof NestedLayoutB2RouteWithChildren } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/nested': { - id: '/nested' - path: '/nested' - fullPath: '/nested' - preLoaderRoute: typeof NestedRouteImport - parentRoute: typeof rootRouteImport - } - '/foo': { - id: '/foo' - path: '/foo' - fullPath: '/foo' - preLoaderRoute: typeof FooRouteImport - parentRoute: typeof rootRouteImport - } '/_layout-a2': { id: '/_layout-a2' path: '' @@ -333,17 +305,17 @@ declare module '@tanstack/react-router' { } '/nested/_layout-b2': { id: '/nested/_layout-b2' - path: '' + path: '/nested' fullPath: '/nested' preLoaderRoute: typeof NestedLayoutB2RouteImport - parentRoute: typeof NestedRoute + parentRoute: typeof rootRouteImport } '/nested/_layout-b1': { id: '/nested/_layout-b1' path: '/nested' fullPath: '/nested' preLoaderRoute: typeof NestedLayoutB1RouteImport - parentRoute: typeof NestedRoute + parentRoute: typeof rootRouteImport } '/jested/_layout-b4': { id: '/jested/_layout-b4' @@ -361,10 +333,10 @@ declare module '@tanstack/react-router' { } '/foo/bar': { id: '/foo/bar' - path: '/bar' + path: '/foo/bar' fullPath: '/foo/bar' preLoaderRoute: typeof FooBarRouteImport - parentRoute: typeof FooRoute + parentRoute: typeof rootRouteImport } '/_layout-a2/bar': { id: '/_layout-a2/bar' @@ -392,7 +364,7 @@ declare module '@tanstack/react-router' { path: '/foo' fullPath: '/foo' preLoaderRoute: typeof FooLayoutB5RouteRouteImport - parentRoute: typeof FooRoute + parentRoute: typeof rootRouteImport } '/nested/_layout-b1/': { id: '/nested/_layout-b1/' @@ -558,18 +530,6 @@ const FooLayoutB5RouteRouteChildren: FooLayoutB5RouteRouteChildren = { const FooLayoutB5RouteRouteWithChildren = FooLayoutB5RouteRoute._addFileChildren(FooLayoutB5RouteRouteChildren) -interface FooRouteChildren { - FooLayoutB5RouteRoute: typeof FooLayoutB5RouteRouteWithChildren - FooBarRoute: typeof FooBarRoute -} - -const FooRouteChildren: FooRouteChildren = { - FooLayoutB5RouteRoute: FooLayoutB5RouteRouteWithChildren, - FooBarRoute: FooBarRoute, -} - -const FooRouteWithChildren = FooRoute._addFileChildren(FooRouteChildren) - interface NestedLayoutB1LayoutC1RouteChildren { NestedLayoutB1LayoutC1BarRoute: typeof NestedLayoutB1LayoutC1BarRoute } @@ -610,27 +570,16 @@ const NestedLayoutB2RouteWithChildren = NestedLayoutB2Route._addFileChildren( NestedLayoutB2RouteChildren, ) -interface NestedRouteChildren { - NestedLayoutB1Route: typeof NestedLayoutB1RouteWithChildren - NestedLayoutB2Route: typeof NestedLayoutB2RouteWithChildren -} - -const NestedRouteChildren: NestedRouteChildren = { - NestedLayoutB1Route: NestedLayoutB1RouteWithChildren, - NestedLayoutB2Route: NestedLayoutB2RouteWithChildren, -} - -const NestedRouteWithChildren = - NestedRoute._addFileChildren(NestedRouteChildren) - const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, JestedRouteRoute: JestedRouteRouteWithChildren, LayoutA1Route: LayoutA1RouteWithChildren, LayoutA2Route: LayoutA2RouteWithChildren, - FooRoute: FooRouteWithChildren, + FooLayoutB5RouteRoute: FooLayoutB5RouteRouteWithChildren, folderInFolderRoute: folderInFolderRoute, - NestedRoute: NestedRouteWithChildren, + FooBarRoute: FooBarRoute, + NestedLayoutB1Route: NestedLayoutB1RouteWithChildren, + NestedLayoutB2Route: NestedLayoutB2RouteWithChildren, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts index c76e88e21d9..6501b213ecc 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts @@ -8,8 +8,6 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { createFileRoute } from '@tanstack/react-router' - import { Route as rootRouteImport } from './routes/__root' import { Route as LayoutA2RouteImport } from './routes/_layout-a2' import { Route as LayoutA1RouteImport } from './routes/_layout-a1' @@ -35,19 +33,6 @@ import { Route as FooLayoutB5IdRouteImport } from './routes/foo/_layout-b5/$id' import { Route as NestedLayoutB1LayoutC1BarRouteImport } from './routes/nested/_layout-b1/_layout-c1/bar' import { Route as JestedLayoutB3LayoutC2BarRouteImport } from './routes/jested/_layout-b3/_layout-c2/bar' -const NestedRouteImport = createFileRoute('/nested')() -const FooRouteImport = createFileRoute('/foo')() - -const NestedRoute = NestedRouteImport.update({ - id: '/nested', - path: '/nested', - getParentRoute: () => rootRouteImport, -} as any) -const FooRoute = FooRouteImport.update({ - id: '/foo', - path: '/foo', - getParentRoute: () => rootRouteImport, -} as any) const LayoutA2Route = LayoutA2RouteImport.update({ id: '/_layout-a2', getParentRoute: () => rootRouteImport, @@ -67,12 +52,14 @@ const IndexRoute = IndexRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const NestedLayoutB2Route = NestedLayoutB2RouteImport.update({ - id: '/_layout-b2', - getParentRoute: () => NestedRoute, + id: '/nested/_layout-b2', + path: '/nested', + getParentRoute: () => rootRouteImport, } as any) const NestedLayoutB1Route = NestedLayoutB1RouteImport.update({ - id: '/_layout-b1', - getParentRoute: () => NestedRoute, + id: '/nested/_layout-b1', + path: '/nested', + getParentRoute: () => rootRouteImport, } as any) const JestedLayoutB4Route = JestedLayoutB4RouteImport.update({ id: '/_layout-b4', @@ -83,9 +70,9 @@ const JestedLayoutB3Route = JestedLayoutB3RouteImport.update({ getParentRoute: () => JestedRouteRoute, } as any) const FooBarRoute = FooBarRouteImport.update({ - id: '/bar', - path: '/bar', - getParentRoute: () => FooRoute, + id: '/foo/bar', + path: '/foo/bar', + getParentRoute: () => rootRouteImport, } as any) const LayoutA2BarRoute = LayoutA2BarRouteImport.update({ id: '/bar', @@ -103,8 +90,9 @@ const folderInFolderRoute = folderInFolderRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const FooLayoutB5RouteRoute = FooLayoutB5RouteRouteImport.update({ - id: '/_layout-b5', - getParentRoute: () => FooRoute, + id: '/foo/_layout-b5', + path: '/foo', + getParentRoute: () => rootRouteImport, } as any) const NestedLayoutB1IndexRoute = NestedLayoutB1IndexRouteImport.update({ id: '/', @@ -177,8 +165,8 @@ export interface FileRoutesByFullPath { export interface FileRoutesByTo { '/': typeof IndexRoute '/jested': typeof JestedLayoutB3IndexRoute - '/foo': typeof FooLayoutB5IndexRoute '/in-folder': typeof folderInFolderRoute + '/foo': typeof FooLayoutB5IndexRoute '/bar': typeof LayoutA2BarRoute '/foo/bar': typeof FooBarRoute '/nested': typeof NestedLayoutB1IndexRoute @@ -194,7 +182,6 @@ export interface FileRoutesById { '/jested': typeof JestedRouteRouteWithChildren '/_layout-a1': typeof LayoutA1RouteWithChildren '/_layout-a2': typeof LayoutA2RouteWithChildren - '/foo': typeof FooRouteWithChildren '/foo/_layout-b5': typeof FooLayoutB5RouteRouteWithChildren '/(folder)/in-folder': typeof folderInFolderRoute '/_layout-a1/foo': typeof LayoutA1FooRoute @@ -202,7 +189,6 @@ export interface FileRoutesById { '/foo/bar': typeof FooBarRoute '/jested/_layout-b3': typeof JestedLayoutB3RouteWithChildren '/jested/_layout-b4': typeof JestedLayoutB4RouteWithChildren - '/nested': typeof NestedRouteWithChildren '/nested/_layout-b1': typeof NestedLayoutB1RouteWithChildren '/nested/_layout-b2': typeof NestedLayoutB2RouteWithChildren '/foo/_layout-b5/$id': typeof FooLayoutB5IdRoute @@ -238,8 +224,8 @@ export interface FileRouteTypes { to: | '/' | '/jested' - | '/foo' | '/in-folder' + | '/foo' | '/bar' | '/foo/bar' | '/nested' @@ -254,7 +240,6 @@ export interface FileRouteTypes { | '/jested' | '/_layout-a1' | '/_layout-a2' - | '/foo' | '/foo/_layout-b5' | '/(folder)/in-folder' | '/_layout-a1/foo' @@ -262,7 +247,6 @@ export interface FileRouteTypes { | '/foo/bar' | '/jested/_layout-b3' | '/jested/_layout-b4' - | '/nested' | '/nested/_layout-b1' | '/nested/_layout-b2' | '/foo/_layout-b5/$id' @@ -282,27 +266,15 @@ export interface RootRouteChildren { JestedRouteRoute: typeof JestedRouteRouteWithChildren LayoutA1Route: typeof LayoutA1RouteWithChildren LayoutA2Route: typeof LayoutA2RouteWithChildren - FooRoute: typeof FooRouteWithChildren + FooLayoutB5RouteRoute: typeof FooLayoutB5RouteRouteWithChildren folderInFolderRoute: typeof folderInFolderRoute - NestedRoute: typeof NestedRouteWithChildren + FooBarRoute: typeof FooBarRoute + NestedLayoutB1Route: typeof NestedLayoutB1RouteWithChildren + NestedLayoutB2Route: typeof NestedLayoutB2RouteWithChildren } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/nested': { - id: '/nested' - path: '/nested' - fullPath: '/nested' - preLoaderRoute: typeof NestedRouteImport - parentRoute: typeof rootRouteImport - } - '/foo': { - id: '/foo' - path: '/foo' - fullPath: '/foo' - preLoaderRoute: typeof FooRouteImport - parentRoute: typeof rootRouteImport - } '/_layout-a2': { id: '/_layout-a2' path: '' @@ -333,17 +305,17 @@ declare module '@tanstack/react-router' { } '/nested/_layout-b2': { id: '/nested/_layout-b2' - path: '' + path: '/nested' fullPath: '/nested' preLoaderRoute: typeof NestedLayoutB2RouteImport - parentRoute: typeof NestedRoute + parentRoute: typeof rootRouteImport } '/nested/_layout-b1': { id: '/nested/_layout-b1' path: '/nested' fullPath: '/nested' preLoaderRoute: typeof NestedLayoutB1RouteImport - parentRoute: typeof NestedRoute + parentRoute: typeof rootRouteImport } '/jested/_layout-b4': { id: '/jested/_layout-b4' @@ -361,10 +333,10 @@ declare module '@tanstack/react-router' { } '/foo/bar': { id: '/foo/bar' - path: '/bar' + path: '/foo/bar' fullPath: '/foo/bar' preLoaderRoute: typeof FooBarRouteImport - parentRoute: typeof FooRoute + parentRoute: typeof rootRouteImport } '/_layout-a2/bar': { id: '/_layout-a2/bar' @@ -392,7 +364,7 @@ declare module '@tanstack/react-router' { path: '/foo' fullPath: '/foo' preLoaderRoute: typeof FooLayoutB5RouteRouteImport - parentRoute: typeof FooRoute + parentRoute: typeof rootRouteImport } '/nested/_layout-b1/': { id: '/nested/_layout-b1/' @@ -558,18 +530,6 @@ const FooLayoutB5RouteRouteChildren: FooLayoutB5RouteRouteChildren = { const FooLayoutB5RouteRouteWithChildren = FooLayoutB5RouteRoute._addFileChildren(FooLayoutB5RouteRouteChildren) -interface FooRouteChildren { - FooLayoutB5RouteRoute: typeof FooLayoutB5RouteRouteWithChildren - FooBarRoute: typeof FooBarRoute -} - -const FooRouteChildren: FooRouteChildren = { - FooLayoutB5RouteRoute: FooLayoutB5RouteRouteWithChildren, - FooBarRoute: FooBarRoute, -} - -const FooRouteWithChildren = FooRoute._addFileChildren(FooRouteChildren) - interface NestedLayoutB1LayoutC1RouteChildren { NestedLayoutB1LayoutC1BarRoute: typeof NestedLayoutB1LayoutC1BarRoute } @@ -610,27 +570,16 @@ const NestedLayoutB2RouteWithChildren = NestedLayoutB2Route._addFileChildren( NestedLayoutB2RouteChildren, ) -interface NestedRouteChildren { - NestedLayoutB1Route: typeof NestedLayoutB1RouteWithChildren - NestedLayoutB2Route: typeof NestedLayoutB2RouteWithChildren -} - -const NestedRouteChildren: NestedRouteChildren = { - NestedLayoutB1Route: NestedLayoutB1RouteWithChildren, - NestedLayoutB2Route: NestedLayoutB2RouteWithChildren, -} - -const NestedRouteWithChildren = - NestedRoute._addFileChildren(NestedRouteChildren) - const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, JestedRouteRoute: JestedRouteRouteWithChildren, LayoutA1Route: LayoutA1RouteWithChildren, LayoutA2Route: LayoutA2RouteWithChildren, - FooRoute: FooRouteWithChildren, + FooLayoutB5RouteRoute: FooLayoutB5RouteRouteWithChildren, folderInFolderRoute: folderInFolderRoute, - NestedRoute: NestedRouteWithChildren, + FooBarRoute: FooBarRoute, + NestedLayoutB1Route: NestedLayoutB1RouteWithChildren, + NestedLayoutB2Route: NestedLayoutB2RouteWithChildren, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts index 7eeca506226..9eea11a3f04 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts @@ -8,23 +8,15 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { createFileRoute } from '@tanstack/react-router' - import { Route as rootRouteImport } from './routes/__root' import { Route as FooLayoutRouteRouteImport } from './routes/foo/_layout/route' import { Route as FooLayoutIndexRouteImport } from './routes/foo/_layout/index' -const FooRouteImport = createFileRoute('/foo')() - -const FooRoute = FooRouteImport.update({ - id: '/foo', +const FooLayoutRouteRoute = FooLayoutRouteRouteImport.update({ + id: '/foo/_layout', path: '/foo', getParentRoute: () => rootRouteImport, } as any) -const FooLayoutRouteRoute = FooLayoutRouteRouteImport.update({ - id: '/_layout', - getParentRoute: () => FooRoute, -} as any) const FooLayoutIndexRoute = FooLayoutIndexRouteImport.update({ id: '/', path: '/', @@ -40,7 +32,6 @@ export interface FileRoutesByTo { } export interface FileRoutesById { __root__: typeof rootRouteImport - '/foo': typeof FooRouteWithChildren '/foo/_layout': typeof FooLayoutRouteRouteWithChildren '/foo/_layout/': typeof FooLayoutIndexRoute } @@ -49,28 +40,21 @@ export interface FileRouteTypes { fullPaths: '/foo' | '/foo/' fileRoutesByTo: FileRoutesByTo to: '/foo' - id: '__root__' | '/foo' | '/foo/_layout' | '/foo/_layout/' + id: '__root__' | '/foo/_layout' | '/foo/_layout/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { - FooRoute: typeof FooRouteWithChildren + FooLayoutRouteRoute: typeof FooLayoutRouteRouteWithChildren } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/foo': { - id: '/foo' - path: '/foo' - fullPath: '/foo' - preLoaderRoute: typeof FooRouteImport - parentRoute: typeof rootRouteImport - } '/foo/_layout': { id: '/foo/_layout' path: '/foo' fullPath: '/foo' preLoaderRoute: typeof FooLayoutRouteRouteImport - parentRoute: typeof FooRoute + parentRoute: typeof rootRouteImport } '/foo/_layout/': { id: '/foo/_layout/' @@ -94,18 +78,8 @@ const FooLayoutRouteRouteWithChildren = FooLayoutRouteRoute._addFileChildren( FooLayoutRouteRouteChildren, ) -interface FooRouteChildren { - FooLayoutRouteRoute: typeof FooLayoutRouteRouteWithChildren -} - -const FooRouteChildren: FooRouteChildren = { - FooLayoutRouteRoute: FooLayoutRouteRouteWithChildren, -} - -const FooRouteWithChildren = FooRoute._addFileChildren(FooRouteChildren) - const rootRouteChildren: RootRouteChildren = { - FooRoute: FooRouteWithChildren, + FooLayoutRouteRoute: FooLayoutRouteRouteWithChildren, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts index 7eeca506226..9eea11a3f04 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts @@ -8,23 +8,15 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { createFileRoute } from '@tanstack/react-router' - import { Route as rootRouteImport } from './routes/__root' import { Route as FooLayoutRouteRouteImport } from './routes/foo/_layout/route' import { Route as FooLayoutIndexRouteImport } from './routes/foo/_layout/index' -const FooRouteImport = createFileRoute('/foo')() - -const FooRoute = FooRouteImport.update({ - id: '/foo', +const FooLayoutRouteRoute = FooLayoutRouteRouteImport.update({ + id: '/foo/_layout', path: '/foo', getParentRoute: () => rootRouteImport, } as any) -const FooLayoutRouteRoute = FooLayoutRouteRouteImport.update({ - id: '/_layout', - getParentRoute: () => FooRoute, -} as any) const FooLayoutIndexRoute = FooLayoutIndexRouteImport.update({ id: '/', path: '/', @@ -40,7 +32,6 @@ export interface FileRoutesByTo { } export interface FileRoutesById { __root__: typeof rootRouteImport - '/foo': typeof FooRouteWithChildren '/foo/_layout': typeof FooLayoutRouteRouteWithChildren '/foo/_layout/': typeof FooLayoutIndexRoute } @@ -49,28 +40,21 @@ export interface FileRouteTypes { fullPaths: '/foo' | '/foo/' fileRoutesByTo: FileRoutesByTo to: '/foo' - id: '__root__' | '/foo' | '/foo/_layout' | '/foo/_layout/' + id: '__root__' | '/foo/_layout' | '/foo/_layout/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { - FooRoute: typeof FooRouteWithChildren + FooLayoutRouteRoute: typeof FooLayoutRouteRouteWithChildren } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/foo': { - id: '/foo' - path: '/foo' - fullPath: '/foo' - preLoaderRoute: typeof FooRouteImport - parentRoute: typeof rootRouteImport - } '/foo/_layout': { id: '/foo/_layout' path: '/foo' fullPath: '/foo' preLoaderRoute: typeof FooLayoutRouteRouteImport - parentRoute: typeof FooRoute + parentRoute: typeof rootRouteImport } '/foo/_layout/': { id: '/foo/_layout/' @@ -94,18 +78,8 @@ const FooLayoutRouteRouteWithChildren = FooLayoutRouteRoute._addFileChildren( FooLayoutRouteRouteChildren, ) -interface FooRouteChildren { - FooLayoutRouteRoute: typeof FooLayoutRouteRouteWithChildren -} - -const FooRouteChildren: FooRouteChildren = { - FooLayoutRouteRoute: FooLayoutRouteRouteWithChildren, -} - -const FooRouteWithChildren = FooRoute._addFileChildren(FooRouteChildren) - const rootRouteChildren: RootRouteChildren = { - FooRoute: FooRouteWithChildren, + FooLayoutRouteRoute: FooLayoutRouteRouteWithChildren, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts b/packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts index f1d7057fd68..f2e84bbbb7e 100644 --- a/packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts +++ b/packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts @@ -20,23 +20,18 @@ import { Route as fooAsdfanotherGroupLayoutRouteImport } from './routes/(foo)/as import { Route as fooAsdfbarLayoutAboutRouteImport } from './routes/(foo)/asdf/(bar)/_layout.about' import { Route as fooAsdfanotherGroupLayoutBazRouteImport } from './routes/(foo)/asdf/(another-group)/_layout.baz' -const fooAsdfRouteImport = createFileRoute('/(foo)/asdf')() const fooAsdfbarLayoutXyzLazyRouteImport = createFileRoute( '/(foo)/asdf/(bar)/_layout/xyz', )() -const fooAsdfRoute = fooAsdfRouteImport.update({ - id: '/(foo)/asdf', - path: '/asdf', - getParentRoute: () => rootRouteImport, -} as any) const barBarRoute = barBarRouteImport.update({ id: '/(bar)/_bar', getParentRoute: () => rootRouteImport, } as any) const fooAsdfLayoutRoute = fooAsdfLayoutRouteImport.update({ - id: '/_layout', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/_layout', + path: '/asdf', + getParentRoute: () => rootRouteImport, } as any) const barBarHelloRoute = barBarHelloRouteImport.update({ id: '/hello', @@ -49,28 +44,29 @@ const fooAsdfLayoutFooRoute = fooAsdfLayoutFooRouteImport.update({ getParentRoute: () => fooAsdfLayoutRoute, } as any) const fooAsdfbarIdRoute = fooAsdfbarIdRouteImport.update({ - id: '/(bar)/$id', - path: '/$id', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(bar)/$id', + path: '/asdf/$id', + getParentRoute: () => rootRouteImport, } as any) const fooAsdfanotherGroupLayoutRoute = fooAsdfanotherGroupLayoutRouteImport.update({ - id: '/(another-group)/_layout', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(another-group)/_layout', + path: '/asdf', + getParentRoute: () => rootRouteImport, } as any) const fooAsdfbarLayoutXyzLazyRoute = fooAsdfbarLayoutXyzLazyRouteImport .update({ - id: '/(bar)/_layout/xyz', - path: '/xyz', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(bar)/_layout/xyz', + path: '/asdf/xyz', + getParentRoute: () => rootRouteImport, } as any) .lazy(() => import('./routes/(foo)/asdf/(bar)/_layout.xyz.lazy').then((d) => d.Route), ) const fooAsdfbarLayoutAboutRoute = fooAsdfbarLayoutAboutRouteImport.update({ - id: '/(bar)/_layout/about', - path: '/about', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(bar)/_layout/about', + path: '/asdf/about', + getParentRoute: () => rootRouteImport, } as any) const fooAsdfanotherGroupLayoutBazRoute = fooAsdfanotherGroupLayoutBazRouteImport.update({ @@ -101,7 +97,6 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/(bar)/_bar': typeof barBarRouteWithChildren '/(bar)/_bar/hello': typeof barBarHelloRoute - '/(foo)/asdf': typeof fooAsdfRouteWithChildren '/(foo)/asdf/_layout': typeof fooAsdfLayoutRouteWithChildren '/(foo)/asdf/(another-group)/_layout': typeof fooAsdfanotherGroupLayoutRouteWithChildren '/(foo)/asdf/(bar)/$id': typeof fooAsdfbarIdRoute @@ -133,7 +128,6 @@ export interface FileRouteTypes { | '__root__' | '/(bar)/_bar' | '/(bar)/_bar/hello' - | '/(foo)/asdf' | '/(foo)/asdf/_layout' | '/(foo)/asdf/(another-group)/_layout' | '/(foo)/asdf/(bar)/$id' @@ -145,18 +139,15 @@ export interface FileRouteTypes { } export interface RootRouteChildren { barBarRoute: typeof barBarRouteWithChildren - fooAsdfRoute: typeof fooAsdfRouteWithChildren + fooAsdfLayoutRoute: typeof fooAsdfLayoutRouteWithChildren + fooAsdfanotherGroupLayoutRoute: typeof fooAsdfanotherGroupLayoutRouteWithChildren + fooAsdfbarIdRoute: typeof fooAsdfbarIdRoute + fooAsdfbarLayoutAboutRoute: typeof fooAsdfbarLayoutAboutRoute + fooAsdfbarLayoutXyzLazyRoute: typeof fooAsdfbarLayoutXyzLazyRoute } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/(foo)/asdf': { - id: '/(foo)/asdf' - path: '/asdf' - fullPath: '/asdf' - preLoaderRoute: typeof fooAsdfRouteImport - parentRoute: typeof rootRouteImport - } '/(bar)/_bar': { id: '/(bar)/_bar' path: '' @@ -169,7 +160,7 @@ declare module '@tanstack/react-router' { path: '/asdf' fullPath: '/asdf' preLoaderRoute: typeof fooAsdfLayoutRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(bar)/_bar/hello': { id: '/(bar)/_bar/hello' @@ -187,31 +178,31 @@ declare module '@tanstack/react-router' { } '/(foo)/asdf/(bar)/$id': { id: '/(foo)/asdf/(bar)/$id' - path: '/$id' + path: '/asdf/$id' fullPath: '/asdf/$id' preLoaderRoute: typeof fooAsdfbarIdRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(another-group)/_layout': { id: '/(foo)/asdf/(another-group)/_layout' - path: '' + path: '/asdf' fullPath: '/asdf' preLoaderRoute: typeof fooAsdfanotherGroupLayoutRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(bar)/_layout/xyz': { id: '/(foo)/asdf/(bar)/_layout/xyz' - path: '/xyz' + path: '/asdf/xyz' fullPath: '/asdf/xyz' preLoaderRoute: typeof fooAsdfbarLayoutXyzLazyRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(bar)/_layout/about': { id: '/(foo)/asdf/(bar)/_layout/about' - path: '/about' + path: '/asdf/about' fullPath: '/asdf/about' preLoaderRoute: typeof fooAsdfbarLayoutAboutRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(another-group)/_layout/baz': { id: '/(foo)/asdf/(another-group)/_layout/baz' @@ -260,29 +251,14 @@ const fooAsdfanotherGroupLayoutRouteWithChildren = fooAsdfanotherGroupLayoutRouteChildren, ) -interface fooAsdfRouteChildren { - fooAsdfLayoutRoute: typeof fooAsdfLayoutRouteWithChildren - fooAsdfanotherGroupLayoutRoute: typeof fooAsdfanotherGroupLayoutRouteWithChildren - fooAsdfbarIdRoute: typeof fooAsdfbarIdRoute - fooAsdfbarLayoutAboutRoute: typeof fooAsdfbarLayoutAboutRoute - fooAsdfbarLayoutXyzLazyRoute: typeof fooAsdfbarLayoutXyzLazyRoute -} - -const fooAsdfRouteChildren: fooAsdfRouteChildren = { +const rootRouteChildren: RootRouteChildren = { + barBarRoute: barBarRouteWithChildren, fooAsdfLayoutRoute: fooAsdfLayoutRouteWithChildren, fooAsdfanotherGroupLayoutRoute: fooAsdfanotherGroupLayoutRouteWithChildren, fooAsdfbarIdRoute: fooAsdfbarIdRoute, fooAsdfbarLayoutAboutRoute: fooAsdfbarLayoutAboutRoute, fooAsdfbarLayoutXyzLazyRoute: fooAsdfbarLayoutXyzLazyRoute, } - -const fooAsdfRouteWithChildren = - fooAsdfRoute._addFileChildren(fooAsdfRouteChildren) - -const rootRouteChildren: RootRouteChildren = { - barBarRoute: barBarRouteWithChildren, - fooAsdfRoute: fooAsdfRouteWithChildren, -} export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() diff --git a/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts b/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts index f1d7057fd68..f2e84bbbb7e 100644 --- a/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts @@ -20,23 +20,18 @@ import { Route as fooAsdfanotherGroupLayoutRouteImport } from './routes/(foo)/as import { Route as fooAsdfbarLayoutAboutRouteImport } from './routes/(foo)/asdf/(bar)/_layout.about' import { Route as fooAsdfanotherGroupLayoutBazRouteImport } from './routes/(foo)/asdf/(another-group)/_layout.baz' -const fooAsdfRouteImport = createFileRoute('/(foo)/asdf')() const fooAsdfbarLayoutXyzLazyRouteImport = createFileRoute( '/(foo)/asdf/(bar)/_layout/xyz', )() -const fooAsdfRoute = fooAsdfRouteImport.update({ - id: '/(foo)/asdf', - path: '/asdf', - getParentRoute: () => rootRouteImport, -} as any) const barBarRoute = barBarRouteImport.update({ id: '/(bar)/_bar', getParentRoute: () => rootRouteImport, } as any) const fooAsdfLayoutRoute = fooAsdfLayoutRouteImport.update({ - id: '/_layout', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/_layout', + path: '/asdf', + getParentRoute: () => rootRouteImport, } as any) const barBarHelloRoute = barBarHelloRouteImport.update({ id: '/hello', @@ -49,28 +44,29 @@ const fooAsdfLayoutFooRoute = fooAsdfLayoutFooRouteImport.update({ getParentRoute: () => fooAsdfLayoutRoute, } as any) const fooAsdfbarIdRoute = fooAsdfbarIdRouteImport.update({ - id: '/(bar)/$id', - path: '/$id', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(bar)/$id', + path: '/asdf/$id', + getParentRoute: () => rootRouteImport, } as any) const fooAsdfanotherGroupLayoutRoute = fooAsdfanotherGroupLayoutRouteImport.update({ - id: '/(another-group)/_layout', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(another-group)/_layout', + path: '/asdf', + getParentRoute: () => rootRouteImport, } as any) const fooAsdfbarLayoutXyzLazyRoute = fooAsdfbarLayoutXyzLazyRouteImport .update({ - id: '/(bar)/_layout/xyz', - path: '/xyz', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(bar)/_layout/xyz', + path: '/asdf/xyz', + getParentRoute: () => rootRouteImport, } as any) .lazy(() => import('./routes/(foo)/asdf/(bar)/_layout.xyz.lazy').then((d) => d.Route), ) const fooAsdfbarLayoutAboutRoute = fooAsdfbarLayoutAboutRouteImport.update({ - id: '/(bar)/_layout/about', - path: '/about', - getParentRoute: () => fooAsdfRoute, + id: '/(foo)/asdf/(bar)/_layout/about', + path: '/asdf/about', + getParentRoute: () => rootRouteImport, } as any) const fooAsdfanotherGroupLayoutBazRoute = fooAsdfanotherGroupLayoutBazRouteImport.update({ @@ -101,7 +97,6 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/(bar)/_bar': typeof barBarRouteWithChildren '/(bar)/_bar/hello': typeof barBarHelloRoute - '/(foo)/asdf': typeof fooAsdfRouteWithChildren '/(foo)/asdf/_layout': typeof fooAsdfLayoutRouteWithChildren '/(foo)/asdf/(another-group)/_layout': typeof fooAsdfanotherGroupLayoutRouteWithChildren '/(foo)/asdf/(bar)/$id': typeof fooAsdfbarIdRoute @@ -133,7 +128,6 @@ export interface FileRouteTypes { | '__root__' | '/(bar)/_bar' | '/(bar)/_bar/hello' - | '/(foo)/asdf' | '/(foo)/asdf/_layout' | '/(foo)/asdf/(another-group)/_layout' | '/(foo)/asdf/(bar)/$id' @@ -145,18 +139,15 @@ export interface FileRouteTypes { } export interface RootRouteChildren { barBarRoute: typeof barBarRouteWithChildren - fooAsdfRoute: typeof fooAsdfRouteWithChildren + fooAsdfLayoutRoute: typeof fooAsdfLayoutRouteWithChildren + fooAsdfanotherGroupLayoutRoute: typeof fooAsdfanotherGroupLayoutRouteWithChildren + fooAsdfbarIdRoute: typeof fooAsdfbarIdRoute + fooAsdfbarLayoutAboutRoute: typeof fooAsdfbarLayoutAboutRoute + fooAsdfbarLayoutXyzLazyRoute: typeof fooAsdfbarLayoutXyzLazyRoute } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/(foo)/asdf': { - id: '/(foo)/asdf' - path: '/asdf' - fullPath: '/asdf' - preLoaderRoute: typeof fooAsdfRouteImport - parentRoute: typeof rootRouteImport - } '/(bar)/_bar': { id: '/(bar)/_bar' path: '' @@ -169,7 +160,7 @@ declare module '@tanstack/react-router' { path: '/asdf' fullPath: '/asdf' preLoaderRoute: typeof fooAsdfLayoutRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(bar)/_bar/hello': { id: '/(bar)/_bar/hello' @@ -187,31 +178,31 @@ declare module '@tanstack/react-router' { } '/(foo)/asdf/(bar)/$id': { id: '/(foo)/asdf/(bar)/$id' - path: '/$id' + path: '/asdf/$id' fullPath: '/asdf/$id' preLoaderRoute: typeof fooAsdfbarIdRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(another-group)/_layout': { id: '/(foo)/asdf/(another-group)/_layout' - path: '' + path: '/asdf' fullPath: '/asdf' preLoaderRoute: typeof fooAsdfanotherGroupLayoutRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(bar)/_layout/xyz': { id: '/(foo)/asdf/(bar)/_layout/xyz' - path: '/xyz' + path: '/asdf/xyz' fullPath: '/asdf/xyz' preLoaderRoute: typeof fooAsdfbarLayoutXyzLazyRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(bar)/_layout/about': { id: '/(foo)/asdf/(bar)/_layout/about' - path: '/about' + path: '/asdf/about' fullPath: '/asdf/about' preLoaderRoute: typeof fooAsdfbarLayoutAboutRouteImport - parentRoute: typeof fooAsdfRoute + parentRoute: typeof rootRouteImport } '/(foo)/asdf/(another-group)/_layout/baz': { id: '/(foo)/asdf/(another-group)/_layout/baz' @@ -260,29 +251,14 @@ const fooAsdfanotherGroupLayoutRouteWithChildren = fooAsdfanotherGroupLayoutRouteChildren, ) -interface fooAsdfRouteChildren { - fooAsdfLayoutRoute: typeof fooAsdfLayoutRouteWithChildren - fooAsdfanotherGroupLayoutRoute: typeof fooAsdfanotherGroupLayoutRouteWithChildren - fooAsdfbarIdRoute: typeof fooAsdfbarIdRoute - fooAsdfbarLayoutAboutRoute: typeof fooAsdfbarLayoutAboutRoute - fooAsdfbarLayoutXyzLazyRoute: typeof fooAsdfbarLayoutXyzLazyRoute -} - -const fooAsdfRouteChildren: fooAsdfRouteChildren = { +const rootRouteChildren: RootRouteChildren = { + barBarRoute: barBarRouteWithChildren, fooAsdfLayoutRoute: fooAsdfLayoutRouteWithChildren, fooAsdfanotherGroupLayoutRoute: fooAsdfanotherGroupLayoutRouteWithChildren, fooAsdfbarIdRoute: fooAsdfbarIdRoute, fooAsdfbarLayoutAboutRoute: fooAsdfbarLayoutAboutRoute, fooAsdfbarLayoutXyzLazyRoute: fooAsdfbarLayoutXyzLazyRoute, } - -const fooAsdfRouteWithChildren = - fooAsdfRoute._addFileChildren(fooAsdfRouteChildren) - -const rootRouteChildren: RootRouteChildren = { - barBarRoute: barBarRouteWithChildren, - fooAsdfRoute: fooAsdfRouteWithChildren, -} export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() From b22c93a130db4aaedbfa4a7ab3fa102359d48f5a Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Wed, 17 Dec 2025 03:03:47 +0100 Subject: [PATCH 2/4] update generated route tree --- .../src/routeTree.gen.ts | 28 +----------- e2e/react-start/basic/src/routeTree.gen.ts | 45 ++++--------------- 2 files changed, 9 insertions(+), 64 deletions(-) diff --git a/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts index 88ecb63891b..170a6beadb7 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts @@ -15,7 +15,6 @@ import { Route as IndexRouteImport } from './routes/index' import { Route as PostsIndexRouteImport } from './routes/posts.index' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' -import { Route as TransitionCountQueryRouteImport } from './routes/transition/count/query' import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' @@ -47,11 +46,6 @@ const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const TransitionCountQueryRoute = TransitionCountQueryRouteImport.update({ - id: '/transition/count/query', - path: '/transition/count/query', - getParentRoute: () => rootRouteImport, -} as any) const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', @@ -70,7 +64,6 @@ export interface FileRoutesByFullPath { '/posts/': typeof PostsIndexRoute '/layout-a': typeof LayoutLayout2LayoutARoute '/layout-b': typeof LayoutLayout2LayoutBRoute - '/transition/count/query': typeof TransitionCountQueryRoute } export interface FileRoutesByTo { '/': typeof IndexRoute @@ -78,7 +71,6 @@ export interface FileRoutesByTo { '/posts': typeof PostsIndexRoute '/layout-a': typeof LayoutLayout2LayoutARoute '/layout-b': typeof LayoutLayout2LayoutBRoute - '/transition/count/query': typeof TransitionCountQueryRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -90,7 +82,6 @@ export interface FileRoutesById { '/posts/': typeof PostsIndexRoute '/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute '/_layout/_layout-2/layout-b': typeof LayoutLayout2LayoutBRoute - '/transition/count/query': typeof TransitionCountQueryRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -101,15 +92,8 @@ export interface FileRouteTypes { | '/posts/' | '/layout-a' | '/layout-b' - | '/transition/count/query' fileRoutesByTo: FileRoutesByTo - to: - | '/' - | '/posts/$postId' - | '/posts' - | '/layout-a' - | '/layout-b' - | '/transition/count/query' + to: '/' | '/posts/$postId' | '/posts' | '/layout-a' | '/layout-b' id: | '__root__' | '/' @@ -120,14 +104,12 @@ export interface FileRouteTypes { | '/posts/' | '/_layout/_layout-2/layout-a' | '/_layout/_layout-2/layout-b' - | '/transition/count/query' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute LayoutRoute: typeof LayoutRouteWithChildren PostsRoute: typeof PostsRouteWithChildren - TransitionCountQueryRoute: typeof TransitionCountQueryRoute } declare module '@tanstack/react-router' { @@ -174,13 +156,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutLayout2RouteImport parentRoute: typeof LayoutRoute } - '/transition/count/query': { - id: '/transition/count/query' - path: '/transition/count/query' - fullPath: '/transition/count/query' - preLoaderRoute: typeof TransitionCountQueryRouteImport - parentRoute: typeof rootRouteImport - } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' @@ -239,7 +214,6 @@ const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, LayoutRoute: LayoutRouteWithChildren, PostsRoute: PostsRouteWithChildren, - TransitionCountQueryRoute: TransitionCountQueryRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/e2e/react-start/basic/src/routeTree.gen.ts b/e2e/react-start/basic/src/routeTree.gen.ts index 0675c8b5f21..a4c81f99f38 100644 --- a/e2e/react-start/basic/src/routeTree.gen.ts +++ b/e2e/react-start/basic/src/routeTree.gen.ts @@ -8,8 +8,6 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { createFileRoute } from '@tanstack/react-router' - import { Route as rootRouteImport } from './routes/__root' import { Route as Char45824Char54620Char48124Char44397RouteImport } from './routes/대한민국' import { Route as UsersRouteImport } from './routes/users' @@ -54,8 +52,6 @@ import { Route as RedirectTargetServerFnViaBeforeLoadRouteImport } from './route import { Route as FooBarQuxHereRouteImport } from './routes/foo/$bar/$qux/_here' import { Route as FooBarQuxHereIndexRouteImport } from './routes/foo/$bar/$qux/_here/index' -const FooBarQuxRouteImport = createFileRoute('/foo/$bar/$qux')() - const Char45824Char54620Char48124Char44397Route = Char45824Char54620Char48124Char44397RouteImport.update({ id: '/대한민국', @@ -203,11 +199,6 @@ const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const FooBarQuxRoute = FooBarQuxRouteImport.update({ - id: '/foo/$bar/$qux', - path: '/foo/$bar/$qux', - getParentRoute: () => rootRouteImport, -} as any) const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', @@ -269,8 +260,9 @@ const RedirectTargetServerFnViaBeforeLoadRoute = getParentRoute: () => RedirectTargetRoute, } as any) const FooBarQuxHereRoute = FooBarQuxHereRouteImport.update({ - id: '/_here', - getParentRoute: () => FooBarQuxRoute, + id: '/foo/$bar/$qux/_here', + path: '/foo/$bar/$qux', + getParentRoute: () => rootRouteImport, } as any) const FooBarQuxHereIndexRoute = FooBarQuxHereIndexRouteImport.update({ id: '/', @@ -350,11 +342,11 @@ export interface FileRoutesByTo { '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute '/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute '/redirect/$target': typeof RedirectTargetIndexRoute - '/foo/$bar/$qux': typeof FooBarQuxHereIndexRoute '/redirect/$target/serverFn/via-beforeLoad': typeof RedirectTargetServerFnViaBeforeLoadRoute '/redirect/$target/serverFn/via-loader': typeof RedirectTargetServerFnViaLoaderRoute '/redirect/$target/serverFn/via-useServerFn': typeof RedirectTargetServerFnViaUseServerFnRoute '/redirect/$target/serverFn': typeof RedirectTargetServerFnIndexRoute + '/foo/$bar/$qux': typeof FooBarQuxHereIndexRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -394,7 +386,6 @@ export interface FileRoutesById { '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute '/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute '/redirect/$target/': typeof RedirectTargetIndexRoute - '/foo/$bar/$qux': typeof FooBarQuxRouteWithChildren '/foo/$bar/$qux/_here': typeof FooBarQuxHereRouteWithChildren '/redirect/$target/serverFn/via-beforeLoad': typeof RedirectTargetServerFnViaBeforeLoadRoute '/redirect/$target/serverFn/via-loader': typeof RedirectTargetServerFnViaLoaderRoute @@ -476,11 +467,11 @@ export interface FileRouteTypes { | '/redirect/$target/via-beforeLoad' | '/redirect/$target/via-loader' | '/redirect/$target' - | '/foo/$bar/$qux' | '/redirect/$target/serverFn/via-beforeLoad' | '/redirect/$target/serverFn/via-loader' | '/redirect/$target/serverFn/via-useServerFn' | '/redirect/$target/serverFn' + | '/foo/$bar/$qux' id: | '__root__' | '/' @@ -519,7 +510,6 @@ export interface FileRouteTypes { | '/redirect/$target/via-beforeLoad' | '/redirect/$target/via-loader' | '/redirect/$target/' - | '/foo/$bar/$qux' | '/foo/$bar/$qux/_here' | '/redirect/$target/serverFn/via-beforeLoad' | '/redirect/$target/serverFn/via-loader' @@ -547,7 +537,7 @@ export interface RootRouteChildren { MultiCookieRedirectIndexRoute: typeof MultiCookieRedirectIndexRoute RedirectIndexRoute: typeof RedirectIndexRoute PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute - FooBarQuxRoute: typeof FooBarQuxRouteWithChildren + FooBarQuxHereRoute: typeof FooBarQuxHereRouteWithChildren } declare module '@tanstack/react-router' { @@ -755,13 +745,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutLayout2RouteImport parentRoute: typeof LayoutRoute } - '/foo/$bar/$qux': { - id: '/foo/$bar/$qux' - path: '/foo/$bar/$qux' - fullPath: '/foo/$bar/$qux' - preLoaderRoute: typeof FooBarQuxRouteImport - parentRoute: typeof rootRouteImport - } '/redirect/$target/': { id: '/redirect/$target/' path: '/' @@ -844,7 +827,7 @@ declare module '@tanstack/react-router' { path: '/foo/$bar/$qux' fullPath: '/foo/$bar/$qux' preLoaderRoute: typeof FooBarQuxHereRouteImport - parentRoute: typeof FooBarQuxRoute + parentRoute: typeof rootRouteImport } '/foo/$bar/$qux/_here/': { id: '/foo/$bar/$qux/_here/' @@ -988,18 +971,6 @@ const FooBarQuxHereRouteWithChildren = FooBarQuxHereRoute._addFileChildren( FooBarQuxHereRouteChildren, ) -interface FooBarQuxRouteChildren { - FooBarQuxHereRoute: typeof FooBarQuxHereRouteWithChildren -} - -const FooBarQuxRouteChildren: FooBarQuxRouteChildren = { - FooBarQuxHereRoute: FooBarQuxHereRouteWithChildren, -} - -const FooBarQuxRouteWithChildren = FooBarQuxRoute._addFileChildren( - FooBarQuxRouteChildren, -) - const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, NotFoundRouteRoute: NotFoundRouteRouteWithChildren, @@ -1020,7 +991,7 @@ const rootRouteChildren: RootRouteChildren = { MultiCookieRedirectIndexRoute: MultiCookieRedirectIndexRoute, RedirectIndexRoute: RedirectIndexRoute, PostsPostIdDeepRoute: PostsPostIdDeepRoute, - FooBarQuxRoute: FooBarQuxRouteWithChildren, + FooBarQuxHereRoute: FooBarQuxHereRouteWithChildren, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) From 4156e3610f6525e195b3f2f211eede4e01b2b160 Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Wed, 17 Dec 2025 03:03:53 +0100 Subject: [PATCH 3/4] format --- packages/router-generator/src/generator.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index afe05345b51..afb42941d1d 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -1409,7 +1409,9 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved acc.routePiecesByPath[node.routePath!] || {} const pieceKey = - node._fsRouteType === 'lazy' ? 'lazy' : (node._fsRouteType as keyof typeof acc.routePiecesByPath[string]) + node._fsRouteType === 'lazy' + ? 'lazy' + : (node._fsRouteType as keyof (typeof acc.routePiecesByPath)[string]) acc.routePiecesByPath[node.routePath!]![pieceKey] = node const anchorRoute = acc.routeNodesByPath.get(node.routePath!) @@ -1436,7 +1438,8 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved // Special handling: pathless layouts with path need to find real ancestor if (!node.isVirtual && isPathlessLayoutWithPath) { - const immediateParentPath = removeLastSegmentFromPath(node.routePath) || '/' + const immediateParentPath = + removeLastSegmentFromPath(node.routePath) || '/' let searchPath = immediateParentPath // Find nearest real (non-virtual, non-index) parent From 8d9efba578ded334395f2c9c5f022d10b61b16df Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Wed, 17 Dec 2025 03:05:15 +0100 Subject: [PATCH 4/4] add e2e test --- .../basic-file-based/src/routeTree.gen.ts | 101 ++++++++++++++++++ .../basic-file-based/src/routes/__root.tsx | 9 ++ .../routes/pathless-layout/_layout/child.tsx | 7 ++ .../routes/pathless-layout/_layout/index.tsx | 7 ++ .../routes/pathless-layout/_layout/route.tsx | 15 +++ .../src/routes/pathless-layout/route.tsx | 15 +++ .../basic-file-based/tests/app.spec.ts | 67 ++++++++++++ 7 files changed, 221 insertions(+) create mode 100644 e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/child.tsx create mode 100644 e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/index.tsx create mode 100644 e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/route.tsx create mode 100644 e2e/react-router/basic-file-based/src/routes/pathless-layout/route.tsx diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts index 83270c2e991..28197e4d987 100644 --- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts @@ -21,6 +21,7 @@ import { Route as AnchorRouteImport } from './routes/anchor' import { Route as LayoutRouteImport } from './routes/_layout' import { Route as Char45824Char54620Char48124Char44397RouteRouteImport } from './routes/대한민국/route' import { Route as SearchParamsRouteRouteImport } from './routes/search-params/route' +import { Route as PathlessLayoutRouteRouteImport } from './routes/pathless-layout/route' import { Route as NonNestedRouteRouteImport } from './routes/non-nested/route' import { Route as IndexRouteImport } from './routes/index' import { Route as SearchParamsIndexRouteImport } from './routes/search-params/index' @@ -39,6 +40,7 @@ import { Route as groupLayoutRouteImport } from './routes/(group)/_layout' import { Route as anotherGroupOnlyrouteinsideRouteImport } from './routes/(another-group)/onlyrouteinside' import { Route as RelativeUseNavigateRouteRouteImport } from './routes/relative/useNavigate/route' import { Route as RelativeLinkRouteRouteImport } from './routes/relative/link/route' +import { Route as PathlessLayoutLayoutRouteRouteImport } from './routes/pathless-layout/_layout/route' import { Route as ParamsPsNonNestedRouteRouteImport } from './routes/params-ps/non-nested/route' import { Route as NonNestedSuffixRouteRouteImport } from './routes/non-nested/suffix/route' import { Route as NonNestedPrefixRouteRouteImport } from './routes/non-nested/prefix/route' @@ -46,6 +48,7 @@ import { Route as NonNestedPathRouteRouteImport } from './routes/non-nested/path import { Route as NonNestedNamedRouteRouteImport } from './routes/non-nested/named/route' import { Route as NonNestedDeepRouteRouteImport } from './routes/non-nested/deep/route' import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' +import { Route as PathlessLayoutLayoutIndexRouteImport } from './routes/pathless-layout/_layout/index' import { Route as ParamsPsWildcardIndexRouteImport } from './routes/params-ps/wildcard/index' import { Route as ParamsPsNamedIndexRouteImport } from './routes/params-ps/named/index' import { Route as Char45824Char54620Char48124Char44397Char55357Char56960IdRouteImport } from './routes/대한민국/🚀.$id' @@ -60,6 +63,7 @@ import { Route as RedirectPreloadFirstRouteImport } from './routes/redirect/prel import { Route as RedirectTargetViaLoaderRouteImport } from './routes/redirect/$target/via-loader' import { Route as RedirectTargetViaBeforeLoadRouteImport } from './routes/redirect/$target/via-beforeLoad' import { Route as PostsPostIdEditRouteImport } from './routes/posts_.$postId.edit' +import { Route as PathlessLayoutLayoutChildRouteImport } from './routes/pathless-layout/_layout/child' import { Route as ParamsSingleValueRouteImport } from './routes/params.single.$value' import { Route as ParamsPsWildcardChar123Char125suffixAtChar45824RouteImport } from './routes/params-ps/wildcard/{$}suffix@대' import { Route as ParamsPsWildcardChar123Char125suffixRouteImport } from './routes/params-ps/wildcard/{$}suffix' @@ -174,6 +178,11 @@ const SearchParamsRouteRoute = SearchParamsRouteRouteImport.update({ path: '/search-params', getParentRoute: () => rootRouteImport, } as any) +const PathlessLayoutRouteRoute = PathlessLayoutRouteRouteImport.update({ + id: '/pathless-layout', + path: '/pathless-layout', + getParentRoute: () => rootRouteImport, +} as any) const NonNestedRouteRoute = NonNestedRouteRouteImport.update({ id: '/non-nested', path: '/non-nested', @@ -267,6 +276,11 @@ const RelativeLinkRouteRoute = RelativeLinkRouteRouteImport.update({ path: '/relative/link', getParentRoute: () => rootRouteImport, } as any) +const PathlessLayoutLayoutRouteRoute = + PathlessLayoutLayoutRouteRouteImport.update({ + id: '/_layout', + getParentRoute: () => PathlessLayoutRouteRoute, + } as any) const ParamsPsNonNestedRouteRoute = ParamsPsNonNestedRouteRouteImport.update({ id: '/params-ps/non-nested', path: '/params-ps/non-nested', @@ -302,6 +316,12 @@ const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ path: '/', getParentRoute: () => RedirectTargetRoute, } as any) +const PathlessLayoutLayoutIndexRoute = + PathlessLayoutLayoutIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => PathlessLayoutLayoutRouteRoute, + } as any) const ParamsPsWildcardIndexRoute = ParamsPsWildcardIndexRouteImport.update({ id: '/params-ps/wildcard/', path: '/params-ps/wildcard/', @@ -379,6 +399,12 @@ const PostsPostIdEditRoute = PostsPostIdEditRouteImport.update({ path: '/posts/$postId/edit', getParentRoute: () => rootRouteImport, } as any) +const PathlessLayoutLayoutChildRoute = + PathlessLayoutLayoutChildRouteImport.update({ + id: '/child', + path: '/child', + getParentRoute: () => PathlessLayoutLayoutRouteRoute, + } as any) const ParamsSingleValueRoute = ParamsSingleValueRouteImport.update({ id: '/params/single/$value', path: '/params/single/$value', @@ -677,6 +703,7 @@ const NonNestedDeepBazBarFooQuxRoute = export interface FileRoutesByFullPath { '/': typeof IndexRoute '/non-nested': typeof NonNestedRouteRouteWithChildren + '/pathless-layout': typeof PathlessLayoutLayoutRouteRouteWithChildren '/search-params': typeof SearchParamsRouteRouteWithChildren '/대한민국': typeof Char45824Char54620Char48124Char44397RouteRouteWithChildren '/anchor': typeof AnchorRoute @@ -729,6 +756,7 @@ export interface FileRoutesByFullPath { '/params-ps/wildcard/{$}suffix': typeof ParamsPsWildcardChar123Char125suffixRoute '/params-ps/wildcard/{$}suffix@대': typeof ParamsPsWildcardChar123Char125suffixAtChar45824Route '/params/single/$value': typeof ParamsSingleValueRoute + '/pathless-layout/child': typeof PathlessLayoutLayoutChildRoute '/posts/$postId/edit': typeof PostsPostIdEditRoute '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute '/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute @@ -743,6 +771,7 @@ export interface FileRoutesByFullPath { '/대한민국/🚀/$id': typeof Char45824Char54620Char48124Char44397Char55357Char56960IdRoute '/params-ps/named': typeof ParamsPsNamedIndexRoute '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute + '/pathless-layout/': typeof PathlessLayoutLayoutIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute '/non-nested/deep/$baz/bar': typeof NonNestedDeepBazBarRouteRouteWithChildren '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren @@ -780,6 +809,7 @@ export interface FileRoutesByFullPath { export interface FileRoutesByTo { '/': typeof IndexRoute '/non-nested': typeof NonNestedRouteRouteWithChildren + '/pathless-layout': typeof PathlessLayoutLayoutIndexRoute '/대한민국': typeof Char45824Char54620Char48124Char44397RouteRouteWithChildren '/anchor': typeof AnchorRoute '/component-types-test': typeof ComponentTypesTestRoute @@ -824,6 +854,7 @@ export interface FileRoutesByTo { '/params-ps/wildcard/{$}suffix': typeof ParamsPsWildcardChar123Char125suffixRoute '/params-ps/wildcard/{$}suffix@대': typeof ParamsPsWildcardChar123Char125suffixAtChar45824Route '/params/single/$value': typeof ParamsSingleValueRoute + '/pathless-layout/child': typeof PathlessLayoutLayoutChildRoute '/posts/$postId/edit': typeof PostsPostIdEditRoute '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute '/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute @@ -874,6 +905,7 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/non-nested': typeof NonNestedRouteRouteWithChildren + '/pathless-layout': typeof PathlessLayoutRouteRouteWithChildren '/search-params': typeof SearchParamsRouteRouteWithChildren '/대한민국': typeof Char45824Char54620Char48124Char44397RouteRouteWithChildren '/_layout': typeof LayoutRouteWithChildren @@ -892,6 +924,7 @@ export interface FileRoutesById { '/non-nested/prefix': typeof NonNestedPrefixRouteRouteWithChildren '/non-nested/suffix': typeof NonNestedSuffixRouteRouteWithChildren '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren + '/pathless-layout/_layout': typeof PathlessLayoutLayoutRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/(another-group)/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -929,6 +962,7 @@ export interface FileRoutesById { '/params-ps/wildcard/{$}suffix': typeof ParamsPsWildcardChar123Char125suffixRoute '/params-ps/wildcard/{$}suffix@대': typeof ParamsPsWildcardChar123Char125suffixAtChar45824Route '/params/single/$value': typeof ParamsSingleValueRoute + '/pathless-layout/_layout/child': typeof PathlessLayoutLayoutChildRoute '/posts_/$postId/edit': typeof PostsPostIdEditRoute '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute '/redirect/$target/via-loader': typeof RedirectTargetViaLoaderRoute @@ -943,6 +977,7 @@ export interface FileRoutesById { '/대한민국/🚀/$id': typeof Char45824Char54620Char48124Char44397Char55357Char56960IdRoute '/params-ps/named/': typeof ParamsPsNamedIndexRoute '/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute + '/pathless-layout/_layout/': typeof PathlessLayoutLayoutIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute '/non-nested/deep/$baz_/bar': typeof NonNestedDeepBazBarRouteRouteWithChildren '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren @@ -982,6 +1017,7 @@ export interface FileRouteTypes { fullPaths: | '/' | '/non-nested' + | '/pathless-layout' | '/search-params' | '/대한민국' | '/anchor' @@ -1034,6 +1070,7 @@ export interface FileRouteTypes { | '/params-ps/wildcard/{$}suffix' | '/params-ps/wildcard/{$}suffix@대' | '/params/single/$value' + | '/pathless-layout/child' | '/posts/$postId/edit' | '/redirect/$target/via-beforeLoad' | '/redirect/$target/via-loader' @@ -1048,6 +1085,7 @@ export interface FileRouteTypes { | '/대한민국/🚀/$id' | '/params-ps/named' | '/params-ps/wildcard' + | '/pathless-layout/' | '/redirect/$target/' | '/non-nested/deep/$baz/bar' | '/params-ps/named/$foo/$bar' @@ -1085,6 +1123,7 @@ export interface FileRouteTypes { to: | '/' | '/non-nested' + | '/pathless-layout' | '/대한민국' | '/anchor' | '/component-types-test' @@ -1129,6 +1168,7 @@ export interface FileRouteTypes { | '/params-ps/wildcard/{$}suffix' | '/params-ps/wildcard/{$}suffix@대' | '/params/single/$value' + | '/pathless-layout/child' | '/posts/$postId/edit' | '/redirect/$target/via-beforeLoad' | '/redirect/$target/via-loader' @@ -1178,6 +1218,7 @@ export interface FileRouteTypes { | '__root__' | '/' | '/non-nested' + | '/pathless-layout' | '/search-params' | '/대한민국' | '/_layout' @@ -1196,6 +1237,7 @@ export interface FileRouteTypes { | '/non-nested/prefix' | '/non-nested/suffix' | '/params-ps/non-nested' + | '/pathless-layout/_layout' | '/relative/link' | '/relative/useNavigate' | '/(another-group)/onlyrouteinside' @@ -1233,6 +1275,7 @@ export interface FileRouteTypes { | '/params-ps/wildcard/{$}suffix' | '/params-ps/wildcard/{$}suffix@대' | '/params/single/$value' + | '/pathless-layout/_layout/child' | '/posts_/$postId/edit' | '/redirect/$target/via-beforeLoad' | '/redirect/$target/via-loader' @@ -1247,6 +1290,7 @@ export interface FileRouteTypes { | '/대한민국/🚀/$id' | '/params-ps/named/' | '/params-ps/wildcard/' + | '/pathless-layout/_layout/' | '/redirect/$target/' | '/non-nested/deep/$baz_/bar' | '/params-ps/named/$foo/$bar' @@ -1285,6 +1329,7 @@ export interface FileRouteTypes { export interface RootRouteChildren { IndexRoute: typeof IndexRoute NonNestedRouteRoute: typeof NonNestedRouteRouteWithChildren + PathlessLayoutRouteRoute: typeof PathlessLayoutRouteRouteWithChildren SearchParamsRouteRoute: typeof SearchParamsRouteRouteWithChildren Char45824Char54620Char48124Char44397RouteRoute: typeof Char45824Char54620Char48124Char44397RouteRouteWithChildren LayoutRoute: typeof LayoutRouteWithChildren @@ -1413,6 +1458,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SearchParamsRouteRouteImport parentRoute: typeof rootRouteImport } + '/pathless-layout': { + id: '/pathless-layout' + path: '/pathless-layout' + fullPath: '/pathless-layout' + preLoaderRoute: typeof PathlessLayoutRouteRouteImport + parentRoute: typeof rootRouteImport + } '/non-nested': { id: '/non-nested' path: '/non-nested' @@ -1539,6 +1591,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof RelativeLinkRouteRouteImport parentRoute: typeof rootRouteImport } + '/pathless-layout/_layout': { + id: '/pathless-layout/_layout' + path: '' + fullPath: '/pathless-layout' + preLoaderRoute: typeof PathlessLayoutLayoutRouteRouteImport + parentRoute: typeof PathlessLayoutRouteRoute + } '/params-ps/non-nested': { id: '/params-ps/non-nested' path: '/params-ps/non-nested' @@ -1588,6 +1647,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof RedirectTargetIndexRouteImport parentRoute: typeof RedirectTargetRoute } + '/pathless-layout/_layout/': { + id: '/pathless-layout/_layout/' + path: '/' + fullPath: '/pathless-layout/' + preLoaderRoute: typeof PathlessLayoutLayoutIndexRouteImport + parentRoute: typeof PathlessLayoutLayoutRouteRoute + } '/params-ps/wildcard/': { id: '/params-ps/wildcard/' path: '/params-ps/wildcard' @@ -1686,6 +1752,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof PostsPostIdEditRouteImport parentRoute: typeof rootRouteImport } + '/pathless-layout/_layout/child': { + id: '/pathless-layout/_layout/child' + path: '/child' + fullPath: '/pathless-layout/child' + preLoaderRoute: typeof PathlessLayoutLayoutChildRouteImport + parentRoute: typeof PathlessLayoutLayoutRouteRoute + } '/params/single/$value': { id: '/params/single/$value' path: '/params/single/$value' @@ -2264,6 +2337,33 @@ const NonNestedRouteRouteWithChildren = NonNestedRouteRoute._addFileChildren( NonNestedRouteRouteChildren, ) +interface PathlessLayoutLayoutRouteRouteChildren { + PathlessLayoutLayoutChildRoute: typeof PathlessLayoutLayoutChildRoute + PathlessLayoutLayoutIndexRoute: typeof PathlessLayoutLayoutIndexRoute +} + +const PathlessLayoutLayoutRouteRouteChildren: PathlessLayoutLayoutRouteRouteChildren = + { + PathlessLayoutLayoutChildRoute: PathlessLayoutLayoutChildRoute, + PathlessLayoutLayoutIndexRoute: PathlessLayoutLayoutIndexRoute, + } + +const PathlessLayoutLayoutRouteRouteWithChildren = + PathlessLayoutLayoutRouteRoute._addFileChildren( + PathlessLayoutLayoutRouteRouteChildren, + ) + +interface PathlessLayoutRouteRouteChildren { + PathlessLayoutLayoutRouteRoute: typeof PathlessLayoutLayoutRouteRouteWithChildren +} + +const PathlessLayoutRouteRouteChildren: PathlessLayoutRouteRouteChildren = { + PathlessLayoutLayoutRouteRoute: PathlessLayoutLayoutRouteRouteWithChildren, +} + +const PathlessLayoutRouteRouteWithChildren = + PathlessLayoutRouteRoute._addFileChildren(PathlessLayoutRouteRouteChildren) + interface SearchParamsRouteRouteChildren { SearchParamsDefaultRoute: typeof SearchParamsDefaultRoute SearchParamsIndexRoute: typeof SearchParamsIndexRoute @@ -2484,6 +2584,7 @@ const ParamsPsNamedFooRouteRouteWithChildren = const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, NonNestedRouteRoute: NonNestedRouteRouteWithChildren, + PathlessLayoutRouteRoute: PathlessLayoutRouteRouteWithChildren, SearchParamsRouteRoute: SearchParamsRouteRouteWithChildren, Char45824Char54620Char48124Char44397RouteRoute: Char45824Char54620Char48124Char44397RouteRouteWithChildren, diff --git a/e2e/react-router/basic-file-based/src/routes/__root.tsx b/e2e/react-router/basic-file-based/src/routes/__root.tsx index da39e29e4e7..dde8139a6e2 100644 --- a/e2e/react-router/basic-file-based/src/routes/__root.tsx +++ b/e2e/react-router/basic-file-based/src/routes/__root.tsx @@ -155,6 +155,15 @@ function RootComponent() { }} > Masks + {' '} + + Pathless Layout
diff --git a/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/child.tsx b/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/child.tsx new file mode 100644 index 00000000000..256ea60e9e4 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/child.tsx @@ -0,0 +1,7 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/pathless-layout/_layout/child')({ + component: () => ( +
Pathless Layout Child Route
+ ), +}) diff --git a/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/index.tsx b/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/index.tsx new file mode 100644 index 00000000000..d6f3e355d9b --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/index.tsx @@ -0,0 +1,7 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/pathless-layout/_layout/')({ + component: () => ( +
Pathless Layout Index
+ ), +}) diff --git a/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/route.tsx b/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/route.tsx new file mode 100644 index 00000000000..ea237a5ea35 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/pathless-layout/_layout/route.tsx @@ -0,0 +1,15 @@ +import { Link, Outlet, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/pathless-layout/_layout')({ + component: () => ( +
+
Pathless Layout Wrapper
+ + +
+ ), +}) diff --git a/e2e/react-router/basic-file-based/src/routes/pathless-layout/route.tsx b/e2e/react-router/basic-file-based/src/routes/pathless-layout/route.tsx new file mode 100644 index 00000000000..de42c745675 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/pathless-layout/route.tsx @@ -0,0 +1,15 @@ +import { Outlet, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/pathless-layout')({ + component: () => ( +
+

Pathless Layout Section

+ +
+ ), + notFoundComponent: () => ( +
+ Not Found in Pathless Layout +
+ ), +}) diff --git a/e2e/react-router/basic-file-based/tests/app.spec.ts b/e2e/react-router/basic-file-based/tests/app.spec.ts index ab11a5fb1c6..6dd1d2559c3 100644 --- a/e2e/react-router/basic-file-based/tests/app.spec.ts +++ b/e2e/react-router/basic-file-based/tests/app.spec.ts @@ -326,3 +326,70 @@ test.describe('Unicode route rendering', () => { expect(page.url()).toBe(`${baseURL}/%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD`) }) }) + +test.describe('Pathless layout routes', () => { + test('direct navigation to pathless layout route renders correctly', async ({ + page, + }) => { + await page.goto('/pathless-layout') + await expect(page.getByTestId('pathless-layout-header')).toContainText( + 'Pathless Layout Section', + ) + await expect(page.getByTestId('pathless-layout-wrapper')).toContainText( + 'Pathless Layout Wrapper', + ) + await expect(page.getByTestId('pathless-layout-index')).toContainText( + 'Pathless Layout Index', + ) + }) + + test('client-side navigation to pathless layout route', async ({ page }) => { + await page.goto('/') + await page.getByTestId('link-to-pathless-layout').click() + await expect(page.getByTestId('pathless-layout-header')).toContainText( + 'Pathless Layout Section', + ) + await expect(page.getByTestId('pathless-layout-wrapper')).toContainText( + 'Pathless Layout Wrapper', + ) + }) + + test('navigation within pathless layout preserves layout', async ({ + page, + }) => { + await page.goto('/pathless-layout') + await page.getByTestId('link-to-child').click() + await expect(page.getByTestId('pathless-layout-header')).toContainText( + 'Pathless Layout Section', + ) + await expect(page.getByTestId('pathless-layout-wrapper')).toContainText( + 'Pathless Layout Wrapper', + ) + await expect(page.getByTestId('pathless-layout-child')).toContainText( + 'Pathless Layout Child Route', + ) + }) + + test('direct navigation to child of pathless layout', async ({ page }) => { + await page.goto('/pathless-layout/child') + await expect(page.getByTestId('pathless-layout-header')).toContainText( + 'Pathless Layout Section', + ) + await expect(page.getByTestId('pathless-layout-wrapper')).toContainText( + 'Pathless Layout Wrapper', + ) + await expect(page.getByTestId('pathless-layout-child')).toContainText( + 'Pathless Layout Child Route', + ) + }) + + test('navigating to non-existent route under pathless layout shows not found', async ({ + page, + }) => { + await page.goto('/pathless-layout/does-not-exist') + await expect(page.getByTestId('pathless-layout-not-found')).toContainText( + 'Not Found in Pathless Layout', + ) + await expect(page.locator('body')).toContainText('Not Found') + }) +})