Skip to content

fix: respect pageExtensions in prerender and exclude _ prefixed api files#591

Merged
james-elicx merged 4 commits intomainfrom
fix/page-extensions-routing-parity
Mar 19, 2026
Merged

fix: respect pageExtensions in prerender and exclude _ prefixed api files#591
james-elicx merged 4 commits intomainfrom
fix/page-extensions-routing-parity

Conversation

@james-elicx
Copy link
Collaborator

Summary

  • run-prerender.ts: pagesRouter/apiRouter were called without pageExtensions, so the prerender phase always scanned with default extensions (tsx,ts,jsx,js) regardless of next.config.js. Now passes config.pageExtensions.
  • cli.ts: Hoisted resolveNextConfig so nextConfig.pageExtensions is forwarded to printBuildReport (previously the result was discarded inline).
  • pages-router.ts (scanApiRoutes): Added _-prefix exclude to match Next.js behaviour — pages/api/_helpers.ts was becoming a /api/_helpers route.
  • report.ts: Tightened printBuildReport signature — pageExtensions is now required (not optional), making callers explicit.

Testing

  • New test in tests/page-extensions-routing.test.ts: verifies _-prefixed files in pages/api/ are excluded.
  • Existing tests in tests/build-report.test.ts (added in prior work): verify printBuildReport respects pageExtensions for both App and Pages Router.
  • All 157 affected tests passing locally.

Notes

With default pageExtensions: ["tsx","ts","jsx","js"], a file like home.spec.tsx in pages/ will still become a route — same as Next.js itself. The correct user-side fix for colocation is pageExtensions: ["page.tsx"], which vinext now respects end-to-end.

…iles

- cli.ts: hoist resolveNextConfig so pageExtensions is passed to printBuildReport
- run-prerender.ts: pass config.pageExtensions to pagesRouter/apiRouter (previously defaulted to ["tsx","ts","jsx","js"] regardless of next.config.js)
- pages-router.ts (scanApiRoutes): add _ prefix exclude, matching pages/ behaviour
- report.ts: tighten printBuildReport signature (pageExtensions required, not optional)
- tests: add coverage for _ prefix exclusion in pages/api and pageExtensions filtering
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 19, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@591

commit: 7c668a8

@github-actions
Copy link

Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original

@james-elicx
Copy link
Collaborator Author

/bigbonk review

@james-elicx james-elicx marked this pull request as ready for review March 19, 2026 17:59
Copy link
Contributor

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Good bug fix — the pageExtensions plumbing was clearly broken in the prerender and build-report paths, and the _-prefix exclusion for API routes is a correct parity fix. The tests are well-structured with proper cleanup. One issue:

Bug: appRouter in run-prerender.ts still missing pageExtensions

The PR fixes pagesRouter/apiRouter calls in run-prerender.ts (lines 227-228) but the appRouter call on line 195 still reads:

const routes = await appRouter(appDir);

This should be:

const routes = await appRouter(appDir, config.pageExtensions);

Without this, the App Router prerender phase still scans with default extensions — the exact same class of bug this PR fixes for Pages Router. A project with pageExtensions: ["page.tsx", "page.ts"] in next.config.js would get phantom app routes during prerender.

Everything else looks correct

  • cli.ts: Hoisting resolveNextConfig is clean — avoids the double-resolve and makes the config available to printBuildReport. The diff is minimal and correct.
  • report.ts: Making pageExtensions required (not optional) is the right call — forces callers to be explicit.
  • pages-router.ts: The _-prefix exclude in scanApiRoutes is consistent with how scanPageRoutes already handles it (line 76). Node.js glob's exclude callback applies to both files and directory entries, so _helpers.ts (file) and _utils/ (directory) are both correctly excluded.
  • Tests: Good coverage — the build-report.test.ts additions verify the end-to-end printBuildReport path with both routers and both include/exclude cases. The page-extensions-routing.test.ts addition specifically tests the _-prefix exclusion. Proper cache invalidation and tmp cleanup throughout.

Minor: afterEach cleanup in build-report.test.ts only invalidates app route cache

In the printBuildReport respects pageExtensions describe block, afterEach calls invalidateAppRouteCache() but not invalidateRouteCache(pagesDir). The pages router tests do call invalidateRouteCache in their finally blocks, so this isn't a correctness issue in practice — but if a pages router test were to fail before reaching finally, the cache wouldn't be cleaned up by afterEach. Consider adding invalidateRouteCache for the pages dir in afterEach too for robustness.

Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
@ask-bonk
Copy link
Contributor

ask-bonk bot commented Mar 19, 2026

Review posted successfully on PR #591. Here's a summary of the findings:

Key issue found: run-prerender.ts:195 — the appRouter(appDir) call is still missing config.pageExtensions, which means the App Router prerender phase has the same bug this PR is fixing for Pages Router. This should be appRouter(appDir, config.pageExtensions).

Everything else is correct:

  • cli.ts hoisting of resolveNextConfig is clean and avoids a double-resolve
  • report.ts making pageExtensions required is the right API tightening
  • pages-router.ts _-prefix exclusion in scanApiRoutes is consistent with how scanPageRoutes already works
  • Tests provide good coverage for both the pageExtensions and _-prefix behaviors

github run

…cache cleanup

- run-prerender.ts: appRouter(appDir) was missing config.pageExtensions, same
  class of bug as the pagesRouter/apiRouter fix — App Router prerender would
  scan with default extensions regardless of next.config.js
- build-report.test.ts: afterEach now invalidates both app and pages route caches
  so a test failure can't leak cached routes into subsequent tests
@james-elicx james-elicx enabled auto-merge (squash) March 19, 2026 18:06
@james-elicx james-elicx merged commit ea08183 into main Mar 19, 2026
25 checks passed
@james-elicx james-elicx deleted the fix/page-extensions-routing-parity branch March 19, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant