Skip to content

fix(router-generator): Pathless Layout Route Renders Empty HTML #4003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
64 changes: 61 additions & 3 deletions packages/router-generator/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,30 @@ export async function generator(config: Config, root: string) {
for (const node of onlyGeneratorRouteNodes) {
await handleNode(node)
}

// Detect empty layout routes and add a virtual index route
const layoutRoutesWithoutIndex = routeNodes.filter((node) => {
if (node._fsRouteType !== 'layout') return false

if (node.children && node.children.length > 0) {
if (node.children.some((child) => child.cleanedPath === '/')) {
return false
}
}
return true
})

// Add a virtual index route to empty layout routes
for (const layoutRoute of layoutRoutesWithoutIndex) {
const virtualIndexRoute = createVirtualIndexRouteWithRedirect(layoutRoute)
routeNodes.push(virtualIndexRoute)
if (!layoutRoute.children) {
layoutRoute.children = []
}
layoutRoute.children.push(virtualIndexRoute)
virtualIndexRoute.parent = layoutRoute
}

checkRouteFullPathUniqueness(
preRouteNodes.filter(
(d) =>
Expand Down Expand Up @@ -529,6 +553,7 @@ export async function generator(config: Config, root: string) {

const imports = Object.entries({
createFileRoute: sortedRouteNodes.some((d) => d.isVirtual),
redirect: routeNodes.some((node) => node.isVirtualRedirectIndex),
lazyFn: sortedRouteNodes.some(
(node) => routePiecesByPath[node.routePath!]?.loader,
),
Expand Down Expand Up @@ -577,9 +602,14 @@ export async function generator(config: Config, root: string) {
virtualRouteNodes.length ? '// Create Virtual Routes' : '',
virtualRouteNodes
.map((node) => {
return `const ${
node.variableName
}Import = createFileRoute('${node.routePath}')()`
if (node.isVirtualRedirectIndex) {
return `const ${node.variableName}Import = createFileRoute('${node.routePath}')({
loader: () => {
redirect({ to: '/', throw: true })
}
})`
}
return `const ${node.variableName}Import = createFileRoute('${node.routePath}')()`
})
.join('\n'),
'// Create/Update Routes',
Expand Down Expand Up @@ -1094,3 +1124,31 @@ export function startAPIRouteSegmentsFromTSRFilePath(

return segments
}

/**
* Creates a virtual index route with a redirect to the root route.
*
* @param parentRoute - The parent layout route that does not have an index route.
* @returns The created virtual index route node.
*/
export const createVirtualIndexRouteWithRedirect = (
parentRoute: RouteNode,
): RouteNode => {
const indexRoutePath = `${parentRoute.routePath}/`
const variableName = routePathToVariable(`${indexRoutePath}index`)

const virtualIndexRoute: RouteNode = {
filePath: '',
fullPath: '',
variableName,
routePath: indexRoutePath,
path: '/',
cleanedPath: '/',
isVirtual: true,
_fsRouteType: 'static',
isVirtualRedirectIndex: true,
redirectTo: '/',
}

return virtualIndexRoute
}
2 changes: 2 additions & 0 deletions packages/router-generator/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export type RouteNode = {
isVirtual?: boolean
children?: Array<RouteNode>
parent?: RouteNode
isVirtualRedirectIndex?: boolean
redirectTo?: string
}

export interface GetRouteNodesResult {
Expand Down
Loading