next.js
7678e6e9 - Stop emitting a redundant route per prefetch segment (#97720)

Commit
2 days ago
Stop emitting a redundant route per prefetch segment (#97720) For a dynamic app page that has a fallback shell, say `/[lang]/[slug]` with a shell for the root param value `de`, the build emits three routes to an adapter. Simplified, with the request pattern on the left and the artifact it resolves to on the right: ```diff - /de/<slug>.segments/$d$lang/$d$slug<seg> -> /de/[slug].segments/$d$lang/$d$slug<seg> /de/<slug><.rsc|.segments/*.segment.rsc> -> /de/[slug]<matched suffix> /de/<slug> -> /de/[slug] ``` This change removes the first one. The second already covers it: its suffix group accepts `.segments/<path>.segment.rsc` as well as `.rsc`, and it copies the matched suffix into the destination, so a per-segment request resolves to the same artifact either way. That second route is also the only one that ever answered `_tree` and `_full` requests, because a per-segment route pins one literal segment path in its regex. A `_tree` prefetch for `/de/<slug>` resolves to `/de/[slug].segments/_tree.segment.rsc`, which the per-segment route cannot produce. So this removes a duplicate, not a mechanism. Only fallback shells emit per-segment routes, because their artifacts sit under an unresolved param and need a rewrite to reach. Segment artifacts for a concrete prerendered path need none, since a request for that path matches them directly. Apps with many shells therefore lose close to a third of their routes. We measured an in-progress feature branch of the v0 chat app, which enumerates precomputed flag, locale and device permutations in `generateStaticParams` for a top-level dynamic segment and so multiplies every route below it. Building that branch before and after the change removes 32% of its routes, adds none, and changes nothing else once the build ID is normalized. This also adds `experimental.collapseAdapterRoutes`. It defaults to `true`, and it controls this collapse together with the ones that follow in this stack. A build that sets it to `false` emits the same route table as a build without any change in this stack. `prefetchSegmentDataRoutes` stays in `routes-manifest.json`. A build that does not use the adapter reads the field from that manifest and derives the same routes from it. This change therefore leaves that path alone. **Verified upstack with a [full deploy test run](https://github.com/vercel/next.js/actions/runs/32540912007).**
Author
Parents
Loading