[PR #447] [MERGED] fix: App Router route-group and slot collision #578

Closed
opened 2026-05-06 13:08:51 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/447
Author: @JaredStowell
Created: 3/11/2026
Status: Merged
Merged: 3/11/2026
Merged by: @james-elicx

Base: mainHead: jstowell/fix-app-route-group-collisions


📝 Commits (5)

  • 4f222c6 Fix app router route-group conflicts
  • c86efe8 Review app router slot discovery
  • af29375 Merge remote-tracking branch 'origin/main' into jstowell/fix-app-route-group-collisions
  • 25db7f7 fix: address review feedback from bonk
  • 91be782 fix: remove now-unused normalizeVisibleRouteSegments, add doc comment to convertSegmentsToRouteParts

📊 Changes

3 files changed (+334 additions, -23 deletions)

View changed files

📝 packages/vinext/src/routing/app-router.ts (+88 -22)
📝 packages/vinext/src/routing/route-validation.ts (+15 -1)
📝 tests/route-sorting.test.ts (+231 -0)

📄 Description

Fix App Router collision handling when multiple filesystem entries resolve to the same visible URL.

This changes route discovery and validation to:

  • reject duplicate normalized route patterns after route-group elision
  • treat /foo and /foo/ as the same route during validation
  • reject grouped slot sub-pages that collapse to the same URL within the same slot
  • reject slot sub-pages that collide with route.ts handlers
  • preserve shadowing semantics for same-named slots at different layout depths
  • merge matching slot sub-pages from different slots onto the same synthesized route

Details

In app-router.ts:

  • track slot ownership with internal ownerDir metadata
  • key synthetic slot merges by (slot name, owner dir) instead of slot name alone
  • normalize visible slot subpaths before duplicate detection
  • throw on page-vs-route-handler collisions
  • stop generating slash-suffixed synthetic patterns for empty/group-only subpaths

In route-validation.ts:

  • canonicalize trailing slashes before duplicate checks and dynamic-route validation

Tests

Added regressions for:

  • duplicate normalized patterns
  • slash-equivalent patterns
  • route-group duplicates like (a)/about vs (b)/about
  • grouped slot sub-page duplicates within one slot
  • grouped slot sub-pages from different slots merging correctly
  • slot sub-pages colliding with route.ts
  • parent slot sub-pages not overwriting a shadowing child slot of the same name

Verification

Passed:

  • pnpm test tests/route-sorting.test.ts
  • pnpm test tests/routing.test.ts
  • pnpm test tests/app-router.test.ts
  • pnpm run fmt
  • pnpm run typecheck

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/447 **Author:** [@JaredStowell](https://github.com/JaredStowell) **Created:** 3/11/2026 **Status:** ✅ Merged **Merged:** 3/11/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `jstowell/fix-app-route-group-collisions` --- ### 📝 Commits (5) - [`4f222c6`](https://github.com/cloudflare/vinext/commit/4f222c69ce0b447046afb8ff8b6b8e44e5dfd487) Fix app router route-group conflicts - [`c86efe8`](https://github.com/cloudflare/vinext/commit/c86efe8ce9e60846c0e7d3e8c8436d153d6fb70e) Review app router slot discovery - [`af29375`](https://github.com/cloudflare/vinext/commit/af29375b76956c04d844237f7f8bd8ef66c0021b) Merge remote-tracking branch 'origin/main' into jstowell/fix-app-route-group-collisions - [`25db7f7`](https://github.com/cloudflare/vinext/commit/25db7f7cb879e8b0084c6ff97d9c2d7ec73d02e3) fix: address review feedback from bonk - [`91be782`](https://github.com/cloudflare/vinext/commit/91be782ee948331faa4c24a4ec20186e9089fcb7) fix: remove now-unused normalizeVisibleRouteSegments, add doc comment to convertSegmentsToRouteParts ### 📊 Changes **3 files changed** (+334 additions, -23 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/routing/app-router.ts` (+88 -22) 📝 `packages/vinext/src/routing/route-validation.ts` (+15 -1) 📝 `tests/route-sorting.test.ts` (+231 -0) </details> ### 📄 Description Fix App Router collision handling when multiple filesystem entries resolve to the same visible URL. This changes route discovery and validation to: - reject duplicate normalized route patterns after route-group elision - treat `/foo` and `/foo/` as the same route during validation - reject grouped slot sub-pages that collapse to the same URL within the same slot - reject slot sub-pages that collide with `route.ts` handlers - preserve shadowing semantics for same-named slots at different layout depths - merge matching slot sub-pages from different slots onto the same synthesized route ## Details In `app-router.ts`: - track slot ownership with internal `ownerDir` metadata - key synthetic slot merges by `(slot name, owner dir)` instead of slot name alone - normalize visible slot subpaths before duplicate detection - throw on page-vs-route-handler collisions - stop generating slash-suffixed synthetic patterns for empty/group-only subpaths In `route-validation.ts`: - canonicalize trailing slashes before duplicate checks and dynamic-route validation ## Tests Added regressions for: - duplicate normalized patterns - slash-equivalent patterns - route-group duplicates like `(a)/about` vs `(b)/about` - grouped slot sub-page duplicates within one slot - grouped slot sub-pages from different slots merging correctly - slot sub-pages colliding with `route.ts` - parent slot sub-pages not overwriting a shadowing child slot of the same name ## Verification Passed: - `pnpm test tests/route-sorting.test.ts` - `pnpm test tests/routing.test.ts` - `pnpm test tests/app-router.test.ts` - `pnpm run fmt` - `pnpm run typecheck` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:08:51 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#578
No description provided.