Files
Hendrik Liebau f8499307ed Fix catch-all router.query corruption with basePath + rewrites (#93294)
In a Pages Router app that combines a `basePath`, `next.config.js`
`rewrites`, middleware, and a catch-all dynamic route, a client-side
`Link` navigation could land on the page with a corrupted
`router.query`. Instead of holding the captured route segments, the
catch-all param ended up holding the segments of the internal
`_next/data/<buildId>/...` URL. Page code that builds further URLs from
`router.query` then produced malformed paths and 404s in production.

The corruption originated in `getMiddlewareData`, which was passing
`nextConfig: undefined` to `getNextPathnameInfo` whenever
`__NEXT_HAS_REWRITES` was true. With basePath set, that meant the
basePath prefix was never stripped from the data-source URL, so the
`/_next/data/` check never matched and the data prefix was left intact.
The resulting pathname flowed back into `routeInfo.resolvedAs`, and on
catch-all routes the route regex matched it and overwrote
`router.query.<param>` with the data-URL segments.

The original ternary at this call site (added in #48753) was there to
avoid stripping the locale prefix, since `resolveRewrites` needs `as` to
keep its locale prefix to match locale-aware rewrite sources. Disabling
all of `nextConfig` was too coarse and broke basePath stripping in the
process. The fix passes a partial config with only `basePath` and
`trailingSlash`, which keeps the locale prefix intact while still
letting `getNextPathnameInfo` strip basePath before the data-prefix
check.

The new `test/e2e/middleware-dynamic-basepath-matcher-rewrites/` fixture
is the catch-all + basePath + rewrites + middleware variant of
`test/e2e/middleware-dynamic-basepath-matcher/` (#48753's regression
test), and asserts that `router.query.path` is preserved across a
client-side `Link` navigation.
2026-05-13 14:50:03 +02:00

9 lines
291 B
JavaScript

module.exports = {
basePath: '/docs',
async rewrites() {
// Any non-empty rewrites array sets __NEXT_HAS_REWRITES=true; this entry
// only exists to flip that build flag, it isn't expected to match.
return [{ source: '/never-matched-rewrite', destination: '/never' }]
},
}