Skip to content

fix(router-core): 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 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/router-core/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3032,6 +3032,7 @@ interface RouteLike {
children?: Array<RouteLike>
options?: {
caseSensitive?: boolean
isVirtualLayout?: boolean
}
}

Expand Down Expand Up @@ -3225,6 +3226,8 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
routeParams = getMatchedParams(foundRoute)!
} else {
foundRoute = flatRoutes.find((route) => {
if (route.options?.isVirtualLayout) return false

const matchedParams = getMatchedParams(route)

if (matchedParams) {
Expand Down
18 changes: 18 additions & 0 deletions packages/router-generator/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,23 @@ export class Generator {
(d) => d,
])

// After all nodes have been processed we can safely (re)-evaluate
// whether a virtual `layout` route should be treated as a virtual-layout wrapper
sortedRouteNodes.forEach((node) => {
if (
node.isVirtual &&
node._fsRouteType === 'layout' &&
node.children &&
!node.children.some((c) => c.cleanedPath === '/')
) {
node.isVirtualLayout = true
} else {
// If the conditions are not met, ensure the flag is falsy so we
// don't rely on an outdated value that may have been set earlier.
delete node.isVirtualLayout
}
})

const pluginConfig = plugin.config({
generator: this,
rootRouteNode,
Expand Down Expand Up @@ -583,6 +600,7 @@ export class Generator {
`id: '${node.path}'`,
!node.isNonPath ? `path: '${node.cleanedPath}'` : undefined,
`getParentRoute: () => ${findParent(node, exportName)}`,
node.isVirtualLayout ? `isVirtualLayout: true` : undefined,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A value is set via update() in the router core to determine whether a route should be matched.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@schiller-manuel
I wanted to implement this in a way that keeps the logic hidden from the user’s code, but I couldn’t come up with a better solution. 😕
I’d appreciate any further suggestions you might have.
If you need a test case, I’d be happy to write one.

]
.filter(Boolean)
.join(',')}
Expand Down
1 change: 1 addition & 0 deletions packages/router-generator/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type RouteNode = {
children?: Array<RouteNode>
parent?: RouteNode
exports?: Array<string>
isVirtualLayout?: boolean
}

export interface GetRouteNodesResult {
Expand Down
Loading