Skip to content

[pull] canary from vercel:canary - #1306

Merged
pull[bot] merged 3 commits into
code:canaryfrom
vercel:canary
Aug 15, 2026
Merged

[pull] canary from vercel:canary#1306
pull[bot] merged 3 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

@pull pull Bot commented Aug 15, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

timneutkens and others added 3 commits August 15, 2026 13:07
### What?

Remove the legacy server route matcher managers, route matcher
providers, and server route matcher classes. Move route definition and
params metadata into fsChecker output and request metadata instead.

### Why?

The filesystem checker already owns the normalized route lookup path in
production. Keeping a separate matcher manager stack duplicates route
inventory, adds reload plumbing, and makes dev and production behavior
harder to keep aligned.

### How?

- Build pages and app route definitions in fsChecker from production
manifests and from the dev route inventory.
- Thread matched route definitions and params through resolve-routes and
router-server request metadata into base-server and next-server.
- Remove reloadMatchers propagation and delete the legacy matcher
manager, provider, and matcher implementations and tests.
- Preserve dev ensurePage behavior, including legacy custom-server
render methods, and Pages API loading by using matched route definitions
while loading compiled dev modules where needed.

### Verification

- `pnpm test-start-webpack test/e2e/custom-routes/custom-routes.test.ts`
- `pnpm test-start-turbo test/e2e/custom-routes/custom-routes.test.ts`
- `pnpm test-dev-webpack test/e2e/custom-routes/custom-routes.test.ts`
- `pnpm test-dev-turbo test/e2e/custom-routes/custom-routes.test.ts`
- `pnpm test-dev-webpack
test/e2e/on-request-error/dynamic-routes/dynamic-routes.test.ts`
- `pnpm test-dev-turbo
test/e2e/on-request-error/dynamic-routes/dynamic-routes.test.ts`
- `pnpm test-start-webpack
test/e2e/app-dir/app-routes/app-custom-routes.test.ts`
- `pnpm test-start-webpack
test/e2e/app-dir/edge-route-rewrite/edge-route-rewrite.test.ts`
- `pnpm test-start-webpack
test/e2e/middleware-rewrites/test/index.test.ts`
- `pnpm test-start-webpack test/e2e/middleware-matcher/index.test.ts
test/e2e/middleware-custom-matchers-basepath/test/index.test.ts
test/e2e/app-dir/rewrites-redirects/rewrites-redirects.test.ts`
- `pnpm test-start-webpack test/e2e/api-catch-all/api-catch-all.test.ts
test/e2e/basepath-root-catch-all/basepath-root-catch-all.test.ts
test/production/root-catchall-cache/root-catchall-cache.test.ts`
- `pnpm test-start-webpack
test/e2e/i18n-beforefiles-rewrite/i18n-beforefiles-rewrite.test.ts`
- `pnpm test-start-webpack
test/e2e/basepath/redirect-and-rewrite.test.ts`
- `pnpm test-dev-webpack test/e2e/custom-server/custom-server.test.ts`
- `pnpm test-start-webpack test/e2e/custom-server/custom-server.test.ts`
- `pnpm --filter=next types`
- `pnpm --filter=next build`
- `git diff --check`

<!-- NEXT_JS_LLM_PR -->
)

Closes #97358

`ResolveResult::with_replaced_request_key` overwrote the `conditions` of
every result key with the conditions of the replacement key (empty at
all call sites). Those conditions are what distinguishes the results one
request resolved to under different export conditions, so both the
`module-sync` and the `default`/`require` target of the same subpath
ended up under the same `RequestKey`.

That is lossy as soon as a request resolves in more than one
`node_modules` directory: the results are merged through a
`RequestKey`-keyed map, so one of the two targets is silently dropped.
With a single candidate directory `ResolveResult::alternatives`
short-circuits and never builds that map, which is why this only showed
up in nested layouts.

In practice this broke `output: 'standalone'` with the Turbopack
production bundler for pnpm installs, whose virtual store hoists every
package into `node_modules/.pnpm/node_modules` and thereby creates that
second candidate directory: `next-server.js.nft.json` recorded only
`@swc/helpers/cjs/_interop_require_default.cjs`, while Node >= 22.12
resolves `@swc/helpers/_/_interop_require_default` to the `module-sync`
target `esm/_interop_require_default.js` (`@swc/helpers` 0.5.23 lists
`module-sync` first). The copied `.next/standalone/server.js` then
exited with MODULE_NOT_FOUND before listening.

---------

Co-authored-by: vercel-fleet[bot] <308483924+vercel-fleet[bot]@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators Aug 15, 2026
@pull pull Bot added the ⤵️ pull label Aug 15, 2026
@pull
pull Bot merged commit b553851 into code:canary Aug 15, 2026
16 of 21 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants