Files
Wyatt JohnsonandGitHub d7608f7ecc Fix prerendering of interception routes with generateStaticParams (#85835)
## What

Fixes a bug where interception routes in parallel slots could not be
prerendered using `generateStaticParams`, causing 404 responses when
these routes were accessed directly.

## Why

**The Problem:**

Interception routes like `app/@modal/(.)photo/[id]/page.tsx` could not
be prerendered even when they exported `generateStaticParams`. This was
because the static path generation code only examined "children"
segments in the loader tree, completely missing segments from parallel
routes (like `@modal`) that actually contribute to the pathname.

**Root Cause:**

The previous implementation used `childrenRouteParamSegments` which only
traversed the `children` branch of the loader tree:

```typescript
// OLD: Only looked at children
const childrenRouteParamSegments = [...segments from children only...]

// This missed parallel routes like @modal that have dynamic segments
```

For a route structure like:
```
app/
  [username]/
    page.tsx
  @modal/
    (.)[username]/
      [id]/
        page.tsx  // ← This route's segments were MISSED
```

The build system couldn't discover the `[id]` parameter in the parallel
route because it never traversed that branch of the tree.

## How

**Solution:**

Introduces `extractPathnameSegments()` which properly traverses the
ENTIRE loader tree (not just children) to find ALL segments that
contribute to the pathname:

1. **BFS Traversal**: Explores both `children` AND all parallel route
slots (e.g., `@modal`, `@sidebar`)

2. **Depth Tracking**: Correctly tracks URL depth by:
   - Skipping route groups `(marketing)` - not in URL
   - Skipping parallel markers `@modal` - not in URL
   - Including interception markers `(.)photo` - ARE in URL

3. **Prefix Validation**: Ensures static segments match the target
pathname before including dynamic segments

4. **Complete Parameter Discovery**: Returns all segments that
contribute to pathname construction, regardless of which tree branch
they're in

**Example:**

For `app/@modal/(.)photo/[id]/page.tsx`:
- Old: Missed the `[id]` parameter entirely
- New: Discovers `[id]` and enables prerendering with
`generateStaticParams`

## Changes

**New Module**: `extract-pathname-segments.ts` (192 lines)
- Core algorithm for traversing loader tree and extracting pathname
segments
- Handles complex cases: parallel routes, interception routes, route
groups
- Well-documented with examples and algorithm explanation

**Comprehensive Tests**: `extract-pathname-segments.test.ts` (897 lines)
- Tests for simple cases, nested structures, parallel routes
- Interception route handling in various configurations
- Route group behavior and edge cases
- Depth tracking validation

**Integration**: `static-paths/app.ts`
- Replaced `childrenRouteParamSegments` with `extractPathnameSegments()`
- Updated pathname construction to use segments from parallel routes
- Maintained backward compatibility

**E2E Test**: Added test validating prerendering works for intercepted
routes

## Test Plan

The new E2E test verifies:
```typescript
it('should prerender a dynamic intercepted route', async () => {
  // Verifies build output contains the prerendered interception route
  expect(next.cliOutput).toContain('/(.)john/1')
  // Verifies it doesn't generate the non-intercepted path
  expect(next.cliOutput).not.toContain('/john/1')
})
```

## Impact

**Before**: Interception routes with dynamic segments returned 404 when
accessed directly, even with `generateStaticParams`

**After**: These routes are properly prerendered at build time and
return correct responses
2025-11-18 09:15:54 -07:00
..