Skip to content

TanStack React: Preserve pathless layout routes - #35135

Closed
MPiland wants to merge 1 commit into
storybookjs:nextfrom
MPiland:fix/tanstack-pathless-layout-routes
Closed

MPiland wants to merge 1 commit into
storybookjs:nextfrom
MPiland:fix/tanstack-pathless-layout-routes

Conversation

@MPiland

@MPiland MPiland commented Jun 10, 2026 •

Copy link
Copy Markdown

What I did

Preserved pure pathless TanStack file routes, such as /_authenticated, as id-only routes in the router mock instead of normalizing them to path: '/'.

This keeps pathless layout routes in the duplicated story router and preserves route ids used by APIs like getRouteApi('/_authenticated/...').

Updated route tree duplication so id-only pathless layout routes stay id-only when cloned, while normal path routes still preserve their original file-route ids after being recreated under the duplicated parent.

The duplicated __root__ route now stays a fresh Storybook preview root and only applies explicit routeOverrides.__root__ options. It no longer copies source app root options, which can include TanStack Start document components such as html, head, body, HeadContent, Scripts, and app providers that are invalid inside Storybook's preview root.

Added an in-repo TanStack framework story that reproduces both the pathless layout route case and the TanStack Start-style document root case.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

The new TanStack framework story covers the manual reproduction path:

  1. Open PathlessLayoutRoutes.stories.tsx in the generated TanStack React Storybook.
  2. Confirm the pathless parent layout renders.
  3. Confirm getRouteApi('/_authenticated/...') can read route context and params from the nested route.
  4. Confirm the TanStack Start-style document root (html, head, body, HeadContent, Scripts, and app providers) is not copied into Storybook's preview root.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Summary by CodeRabbit

  • New Features

    • Enhanced support for pathless layout routes, enabling better handling of layout-only segments that don't contribute to URL paths.
  • Bug Fixes

    • Improved route tree cloning and duplication behavior to correctly preserve route identity and context injection for pathless layouts.
  • Tests

    • Expanded test coverage for pathless layout route scenarios, including nested routes and route state preservation during tree duplication.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 826dc355-41d7-4370-9ead-87f8013317fa

📥 Commits

Reviewing files that changed from the base of the PR and between 723b09d and 97062f8.

📒 Files selected for processing (5)
  • code/frameworks/tanstack-react/src/export-mocks/react-router.test.ts
  • code/frameworks/tanstack-react/src/export-mocks/react-router.ts
  • code/frameworks/tanstack-react/src/routing/duplicate-tree.test.ts
  • code/frameworks/tanstack-react/src/routing/duplicate-tree.ts
  • code/frameworks/tanstack-react/template/stories/PathlessLayoutRoutes.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • code/frameworks/tanstack-react/src/export-mocks/react-router.test.ts
  • code/frameworks/tanstack-react/template/stories/PathlessLayoutRoutes.stories.tsx
  • code/frameworks/tanstack-react/src/export-mocks/react-router.ts
  • code/frameworks/tanstack-react/src/routing/duplicate-tree.test.ts

📝 Walkthrough

Walkthrough

Adds special-case handling in createFileRoute to detect pure pathless _layout routes (last segment starts with _ and normalized path is /) and emit id-only route options. Updates cloneChild and duplicateRouteTree to correctly preserve or omit id/path during route tree duplication. Introduces a new Storybook story validating pathless layout context and params preservation end-to-end.

Changes

Pathless Layout Route Handling

Layer / File(s) Summary
Mock route creation for pathless layouts
code/frameworks/tanstack-react/src/export-mocks/react-router.ts, code/frameworks/tanstack-react/src/export-mocks/react-router.test.ts
createFileRoute detects pure pathless routes when last segment starts with _ and normalized path is /, then emits createRoute/update calls with only id set (omitting path/fullPath). Test mocks storybook/test via vi.mock and asserts build('/_layout') yields an id-only route.
Route tree duplication for pathless layouts
code/frameworks/tanstack-react/src/routing/duplicate-tree.ts, code/frameworks/tanstack-react/src/routing/duplicate-tree.test.ts
cloneChild passes id into createRoute only for pathless routes and restores it via cloned.update({ id }) for path-based routes. duplicateRouteTree now builds the new root with only __root__ overrides. Tests cover root option isolation, override application, and correct state.matches IDs after router.load().
Storybook story for pathless layout validation
code/frameworks/tanstack-react/template/stories/PathlessLayoutRoutes.stories.tsx
Adds a route tree with DocumentRoot, pathless AuthenticatedRoute injecting sessionLabel via beforeLoad, nested RaceRoute with dynamic params, and a RouteStateProbe leaf. Story play function asserts layout rendering and context/params text, and asserts document-root/app-providers are absent.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • storybookjs/storybook#34948: Both PRs modify the createFileRoute mock to change how underscore-prefixed segments affect path/fullPath vs id; this PR adds the "pure pathless" special case that extends the normalization logic from that PR.
  • storybookjs/storybook#34950: Both PRs fix synthetic route construction to correctly manage the relationship between id and path, with this PR specifically addressing the id-only pathless layout case.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@MPiland

MPiland commented Jun 10, 2026

Copy link
Copy Markdown
Author

Danger is currently blocked on labels. I do not have permission to add them from the fork; the requested sets appear to be: category \�ug, CI \ci:normal, and QA \qa:needed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
code/frameworks/tanstack-react/src/routing/duplicate-tree.ts (1)

64-98: ⚖️ Poor tradeoff

Consider investigating stricter typing for route options (optional).

The function uses several any type assertions (lines 64, 76-81, 84) to work with TanStack Router's internal option types. While this is functional and may be necessary given TanStack's type system, stricter typing could improve type safety and IDE support if TanStack exports suitable utility types for route manipulation.

However, this appears to be a broader pattern in the codebase and would require coordination with TanStack Router's type system design, so it's reasonable to defer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/frameworks/tanstack-react/src/routing/duplicate-tree.ts` around lines 64
- 98, The code relies on repeated any casts for route options and cloning which
weakens type safety; replace the broad any usages by importing/using TanStack
Router's specific option types (e.g., the FileRoute or Route option/interface
types) for variables like options, the createRoute call payload, cloned,
children and cloneChild parameters, and the byId map value (instead of AnyRoute
any-casts), and adjust the getParentRoute override and update/addChildren calls
to use those concrete types; specifically, change the declarations that
currently cast (oldRoute as any).options, the createRoute argument, the cloned
variable, children typing, and cloneChild signature to use the library's
exported route option/route instance types and update getOverrideFor/overrides
to return correctly typed partial option overrides so you can remove the casts
around createRoute, cloned.update, cloned.addChildren and byId.set.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@code/frameworks/tanstack-react/src/routing/duplicate-tree.ts`:
- Around line 64-98: The code relies on repeated any casts for route options and
cloning which weakens type safety; replace the broad any usages by
importing/using TanStack Router's specific option types (e.g., the FileRoute or
Route option/interface types) for variables like options, the createRoute call
payload, cloned, children and cloneChild parameters, and the byId map value
(instead of AnyRoute any-casts), and adjust the getParentRoute override and
update/addChildren calls to use those concrete types; specifically, change the
declarations that currently cast (oldRoute as any).options, the createRoute
argument, the cloned variable, children typing, and cloneChild signature to use
the library's exported route option/route instance types and update
getOverrideFor/overrides to return correctly typed partial option overrides so
you can remove the casts around createRoute, cloned.update, cloned.addChildren
and byId.set.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fbb90587-e03a-47cc-b290-e421206494ee

📥 Commits

Reviewing files that changed from the base of the PR and between 564c477 and ff5b6a1.

📒 Files selected for processing (2)
  • code/frameworks/tanstack-react/src/routing/duplicate-tree.test.ts
  • code/frameworks/tanstack-react/src/routing/duplicate-tree.ts

@Sidnioulz Sidnioulz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for your PR @MPiland!

Could you please help us to review it by providing a reproduction repository (e.g. using http://storybook.new/)?

The testing steps you provided are great (thanks!) but we still get a lot of PRs, so manually recreating reproductions makes it harder for us to review PRs quickly and with confidence.

Also, it looks like you could actually create config and stories with play functions to directly test your change within the repo. Stories and E2E tests are an acceptable form of reproduction for us, so you could also submit a story in the tanstack framework stories that matches your manual testing setup, and asserts everything renders as intended.

Thanks 🙏

@Sidnioulz Sidnioulz added bug ci:normal Run our default set of CI jobs (choose this for most PRs). tanstack qa:skip Pull Requests that do not need any QA. (e.g. documentation) labels Jun 11, 2026
@Sidnioulz Sidnioulz self-assigned this Jun 11, 2026
@Sidnioulz Sidnioulz moved this to On Hold in Core Team Projects Jun 11, 2026
@storybook-app-bot

storybook-app-bot Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 97062f8, ran on 17 June 2026 at 16:35:44 UTC

The following packages have significant changes to their size or dependencies:

storybook

Before After Difference
Dependency count 72 72 0
Self size 21.07 MB 21.07 MB 0 B
Dependency size 36.41 MB 36.43 MB 🚨 +25 KB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 204 204 0
Self size 802 KB 802 KB 0 B
Dependency size 91.40 MB 91.43 MB 🚨 +25 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 197 197 0
Self size 32 KB 32 KB 🎉 -36 B 🎉
Dependency size 89.90 MB 89.92 MB 🚨 +25 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 73 73 0
Self size 1.08 MB 1.08 MB 🎉 -66 B 🎉
Dependency size 57.48 MB 57.51 MB 🚨 +25 KB 🚨
Bundle Size Analyzer node node

@MPiland

MPiland commented Jun 12, 2026

Copy link
Copy Markdown
Author

Thanks for your PR @MPiland!

Could you please help us to review it by providing a reproduction repository (e.g. using http://storybook.new/)?

The testing steps you provided are great (thanks!) but we still get a lot of PRs, so manually recreating reproductions makes it harder for us to review PRs quickly and with confidence.

Also, it looks like you could actually create config and stories with play functions to directly test your change within the repo. Stories and E2E tests are an acceptable form of reproduction for us, so you could also submit a story in the tanstack framework stories that matches your manual testing setup, and asserts everything renders as intended.

Thanks 🙏

Thanks! I added an in-repo reproduction story under the TanStack framework template:

code/frameworks/tanstack-react/template/stories/PathlessLayoutRoutes.stories.tsx

It covers the pathless layout route case with a nested child route and play assertions for:

  • the pathless parent layout rendering
  • the nested route rendering
  • getRouteApi('/_authenticated/...') reading route context/params
  • the source app root document component not being copied into Storybook’s preview root

I validated the package with:

  • yarn nx check tanstack-react
  • yarn vitest run --config code/frameworks/tanstack-react/vitest.config.ts code/frameworks/tanstack-react/src/routing/duplicate-tree.test.ts code/frameworks/tanstack-react/src/export-mocks/react-router.test.ts

I also generated the tanstack-react-router/default-ts sandbox and confirmed the new template story is copied into the generated reproduction.

@MPiland
MPiland requested a review from Sidnioulz June 15, 2026 20:27
@Sidnioulz
Sidnioulz requested a review from huang-julien June 16, 2026 14:07
@Sidnioulz Sidnioulz assigned huang-julien and unassigned Sidnioulz Jun 16, 2026

@huang-julien huang-julien left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

While the fix works, the PR has unrelated changes.

Please disclose if/how did you use codex/AI agent on this PR.

Comment thread code/frameworks/tanstack-react/src/preset.ts Outdated
Comment thread code/frameworks/tanstack-react/src/routing/duplicate-tree.ts
Comment thread code/frameworks/tanstack-react/src/routing/decorator.tsx Outdated
@MPiland
MPiland force-pushed the fix/tanstack-pathless-layout-routes branch from 723b09d to 97062f8 Compare June 17, 2026 16:17
@MPiland
MPiland requested a review from huang-julien June 17, 2026 16:22
@huang-julien

huang-julien commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Hi,

i'm closing this PR as it still involves multiple differents fixes. Please open smaller PRs that fixes a single bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-scan:human bug ci:normal Run our default set of CI jobs (choose this for most PRs). qa:skip Pull Requests that do not need any QA. (e.g. documentation) tanstack

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants