refactor(routing): extract App Router route graph builder#998
Conversation
commit: |
|
/bigbonk review |
There was a problem hiding this comment.
Clean extraction. The move is mechanically faithful — I diffed the original appRouter body against the new buildAppRouteGraph and the only intentional change is dropping the unused _appDir parameter from discoverSlotSubRoutes. All 11 consumers of AppRoute and the single consumer of computeRootParamNames continue to import from app-router.ts via the re-exports, so nothing breaks downstream. ParallelSlot and InterceptingRoute have zero direct importers outside the routing module, so omitting them from the re-exports is correct.
Two minor observations below — neither is blocking.
| }); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Nit: The test covers the happy path well (pages, route handlers, layouts, inherited parallel slots). If you want to strengthen the graph-builder test as a follow-up, consider adding cases for:
- Synthetic parallel slot sub-routes (
@slot/subpage/page.tsxcreating a new URL route) - Route group transparency (e.g.
(marketing)/about/page.tsx→/about) page.tsx+route.tsconflict at the same segment (should throw)
These are already covered by the existing routing.test.ts suite so nothing is at risk here — it's just a matter of whether you want buildAppRouteGraph to be independently testable for those behaviors without going through the appRouter cache wrapper.
| export async function buildAppRouteGraph( | ||
| appDir: string, | ||
| matcher: ValidFileMatcher, | ||
| ): Promise<{ routes: AppRoute[] }> { |
There was a problem hiding this comment.
Nit: The return type Promise<{ routes: AppRoute[] }> wraps the array in an object. Right now routes is the only field, so appRouter immediately unwraps it with graph.routes. If you anticipate adding more graph metadata later (e.g. a manifest hash, diagnostic warnings, or the root layout path), the object wrapper makes sense as a forward-compatible seam. If not, returning AppRoute[] directly would be simpler. Either way is fine — just flagging the trade-off.
|
Review submitted. Here's a summary of what I found: Approved. This is a clean mechanical extraction with no behavioral changes. Key findings:
Two minor nits posted:
|
App Router route discovery currently shares a single module with route caching and request-time matching. That makes discovery changes harder to review and increases the chance that graph construction work collides with generated entry changes. The route graph construction types and discovery helpers now live in app-route-graph.ts, while app-router.ts remains the public cache and trie matching wrapper. A direct graph-builder test covers pages, route handlers, layouts, and inherited parallel slots at the new boundary.
4d80675 to
3f2072b
Compare
What this changes
Extracts App Router route graph construction into
packages/vinext/src/routing/app-route-graph.ts.app-router.tsnow stays focused on the publicappRouter()cache wrapper and request-time trie matching, while the new graph builder owns filesystem scanning, route metadata materialization, validation, synthetic parallel slot routes, and exported route shape types.Why
Will make #726 easier
The App Router routing module had grown into a mixed-purpose file that combined discovery, graph materialization, cache ownership, and request matching. That made route graph changes noisy to review and more likely to collide with App Router runtime entry work.
This keeps the graph-building pressure isolated inside routing code and avoids touching generated entry templates such as
entries/app-rsc-entry.ts.Approach
routing/app-route-graph.ts.buildAppRouteGraph(appDir, matcher)as the direct construction boundary.appRouter()behavior-compatible by delegating to the builder, then caching the returned routes as before.matchAppRoute()and trie caching inapp-router.ts, since those are request-time matching concerns rather than graph construction concerns.Validation
vp test run tests/app-route-graph.test.ts tests/routing.test.ts tests/route-sorting.test.ts tests/page-extensions-routing.test.tsvp run vinext#builddist/routing/app-route-graph.jsvp checkNote: the first
vp checkrun happened before the package build had generated workspace package output and failed onbenchmarks/vinext/vite.config.tsresolvingvinext. Aftervp run vinext#build, rerunningvp checkpassed.Risks / follow-ups
The main risk is accidental drift in synthetic parallel slot route materialization. I covered that with the new graph-builder test plus the existing routing and route sorting suites that exercise slot inheritance, conflict errors, intercepting routes, catch-all validation, and route ordering.
No generated App Router entry files are touched in this PR.