Storybook TanStack Router integration: Nested file routes throw Duplicate routes found with id: __root__ unless routeTree.gen is imported via side-effect #36376
Replies: 2 comments 9 replies
This comment was marked as low quality.
This comment was marked as low quality.
|
What Storybook framework is configured in .storybook/main.ts, and which Storybook version are you on? The specific error you're seeing ( The reason that matters: Now to answer the above questions (assuming 1. Is importing For rendering a route inside its parent layouts, yes, and you're right that we don't say so. A file route holds no reference to its parent until // .storybook/preview.ts
import '@/routeTree.gen';After that, 2. How do you pass The shape in the reply above isn't right: there is no The full-tree form is to pass the tree as import { routeTree } from '@/routeTree.gen';
const meta = preview.meta({
parameters: {
tanstack: {
router: {
route: routeTree,
path: '/take-a-break-confirmation',
},
},
},
});That said, if you're on 10.5.x this will misbehave exactly as you observed. Leaf selection compared Since your route uses If you can share your Storybook version and framework, I'm happy to confirm which of the above applies to your setup. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Hello! I'm running into an issue using the official Storybook TanStack Router integration in a pure client-side SPA setup with file-based routing.
I want to verify whether I am misinterpreting the recommended usage pattern for nested routes or if we have hit a bug/edge case in the addon's tree resolution logic. Given that our setup is a standard TanStack Router SPA using file-based routes (with an autogenerated
routeTree.gen.ts), this feels like a primary use case that should work cleanly out of the box.According to the Storybook documentation for rendering nested file routes:
We attempted to import our nested page route directly into the story:
Where
Routeis a simple TanStack route definition:With this setup, the story fails at runtime with:
I investigated what's going on under the hood and didn't find any code that attempts to load ancestors for the passed route.
The issue seems to happen because Storybook creates a synthetic root and then attaches the passed route to it. The passed route doesn't have an
idyet (because it is assigned as a side effect insiderouteTree.gen.ts, which isn't imported in this story). As a result, two routes without anidare treated as duplicate__root__routes.The docs mention as an alternative:
However, while the docs mention this, they don't provide an example showing how to pass
routeTreeproperly. I attempted the following:The invariant error disappears, but the story still fails to render the target path correctly. Instead of rendering the route associated with the
/take-a-break-confirmationpath within the tree, the addon injects the story component at the resolved leaf route, resulting in the root route rendering twice.The only working approach I have found is forcing a side-effectful import of
routeTree.gen.tsto assemble the route tree first:This works because in TanStack Router's file-based approach, route definitions don't contain links to parents or children until
routeTree.gen.tsis loaded.The typical content of
routeTree.gen.tslooks like this:This file mutates the route definitions and assembles the tree. Once loaded, the Storybook integration can traverse ancestors starting from the passed leaf route and locate the root route correctly.
Questions / Feedback:
routeTree.gen.tsto load intended to be the standard usage pattern? If so, could this be explicitly stated in the documentation? If not, what is the intended way to render a route alongside all its ancestors in Storybook?routeTreebe passed alongside a specificRoute? TherouteTreeexported fromrouteTree.gen.tsis essentially the root route, so passing it intoparameters.tanstack.router.routecauses the story to render the root route instead of the target page route.Thanks for the clarification and for your great work on Storybook!
Additional information
No response
Create a reproduction
No response
All reactions