Skip to content

[pull] canary from vercel:canary - #1395

Merged
pull[bot] merged 7 commits into
code:canaryfrom
vercel:canary
Sep 14, 2026
Merged

pull[bot] merged 7 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

@pull pull Bot commented Sep 14, 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 : )

devjiwonchoi and others added 7 commits September 14, 2026 16:15
Ported from #98040 by @marcoshernanz.

> [!TIP]
> Best reviewed commit by commit.

### Why?

External development tools need browser runtime-error state, not just
build errors, to display application failures. Reporting remains opt-in
so applications that do not need it avoid client serialization, HMR
transport, server formatting, buffering, and rebroadcast overhead.

### How?

Add `experimental.exposeRuntimeErrorsToHMR` for App Router development
with Webpack and Turbopack. Internal integrations can also enable the
same behavior without changing `next.config` by setting
`__NEXT_EXPOSE_RUNTIME_ERRORS_TO_HMR` to any non-empty value. When
enabled, the HMR WebSocket emits `runtimeErrors` snapshots containing:

- The current pathname and browser client/document identifiers.
- Error types, names, messages, and source-mapped stacks.
- Fatality and optional catching-boundary details (`default-global`,
`custom-global`, or `custom`).

Snapshots update as errors and navigation change. New or reconnected
observers receive the current state, and disconnecting a browser clears
its reported errors. An empty snapshot means there are no currently
reported errors; it does not guarantee application recovery.

Reporting is disabled by default. Pages Router, MCP `get_errors`, and
production behavior are unchanged.

<!-- NEXT_JS_LLM -->

Co-authored-by: Marcos Hernanz
<96699542+marcoshernanz@users.noreply.github.com>
## Maintainer status

- Current with `canary` as of 2026-05-18; this branch includes a clean
merge from latest `origin/canary`.
- Lightweight checks pass; full fork workflows are still
`action_required` until a maintainer approves CI.
- No unresolved review threads or failing jobs are reported after the
refresh.
- Review focus: shared convention-file basename extraction for proxy,
middleware, and instrumentation under compound `pageExtensions`; TS and
Rust paths use the same rule.

---

## Summary

Fixes #85648
Fixes #86303
Fixes #91600
Fixes #85646
Related to #86122
Fixes #92342
Closes #92934

When `pageExtensions` is set to compound extensions like `['page.ts',
'page.tsx']`, proxy files must be named `proxy.page.ts`. However, the
proxy detection logic used `file_stem()` (Rust/Turbopack) and
`path.parse().name` (JS/webpack), both of which only strip the **last**
extension — so `proxy.page.ts` becomes `proxy.page` instead of `proxy`,
and the proxy is never detected.

**Root cause:** `path.parse('proxy.page.ts').name` returns
`'proxy.page'`, not `'proxy'`. Same issue with Rust's `file_stem()`
which uses `rsplit_once('.')`.

**Fix:** Use `file_name().split('.')[0]` (JS) /
`file_name().split('.').next()` (Rust) to extract the first segment
before any dot. This correctly returns `'proxy'` for both `proxy.ts` and
`proxy.page.ts`.

The same `fileBaseName` extraction is also used for `middleware` and
`instrumentation` convention file detection, fixing compound
pageExtensions for those as well.

### Changes

- **Turbopack (Rust):** `crates/next-api/src/project.rs` (2 locations) +
`crates/next-api/src/middleware.rs` (1 location)
- **Webpack (JS):** `packages/next/src/build/index.ts` (build-time
detection) +
`packages/next/src/server/lib/router-utils/setup-dev-bundler.ts`
(dev-time detection)
- **E2e tests:**
- `proxy-page-extensions/` — proxy + instrumentation with compound
extensions
- `middleware-page-extensions/` — middleware with compound extensions
(separate fixture because the build refuses both `proxy.*` and
`middleware.*` simultaneously)

### Verified locally

| Mode | Bundler | Result |
|------|---------|--------|
| Dev | Turbopack | PASS (5/5) |
| Dev | Webpack | PASS (5/5) |
| Production (build+start) | Turbopack | PASS (5/5) |
| Production (build+start) | Webpack | PASS (5/5) |

Existing proxy test suites also verified (proxy-runtime-nodejs,
proxy-with-middleware, proxy-missing-export, proxy-runtime) — no
regressions.

## Test plan

- [x] `proxy-page-extensions.test.ts` covers proxy header injection,
page render through proxy, and `instrumentation.page.ts:register()`
running
- [x] `middleware-page-extensions.test.ts` covers middleware header
injection and page render through middleware
- [x] All 5 cases pass in dev/turbopack, dev/webpack, start/turbopack,
start/webpack
- [x] Existing proxy-runtime-nodejs tests pass (dev/webpack,
dev/turbopack, production/webpack)
- [ ] CI passes on all existing proxy tests

<!-- NEXT_JS_LLM_PR -->

---------

Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>
## Summary

Turbopack previously widened export usage to every export when a Server
Component crossed a client-component proxy. As a result, importing one
named export from a `use client` module retained unrelated
implementations in both browser and SSR bundles.

This extends Turbopack's import annotations with a generic export-usage
passthrough. The server transform for `use client` modules marks its
generated namespace import as passthrough, so the ordinary binding-usage
fixed point carries the Server Component's used export set into
`EcmascriptClientReferenceModule`. Its client-reference edges use the
same signal to forward that set to browser and SSR targets.
Side-effect-only evaluation references retain their evaluation semantics
instead of inheriting the annotation. The forwarded names remain
namespace-observable because React Flight resolves client references by
their original export names, so unused exports can be removed without
changing the protocol-visible identity. An importer whose usage is `All`
still forwards `All`.

The client-component tree-shaking test now checks that unused markers
are absent from every browser chunk and verifies the same behavior in
Turbopack SSR chunks.

## Verification

- `cargo fmt --all -- --check`
- `cargo check -p next-core`
- `cargo test -p turbopack-core module_graph::binding_usage_info::tests
--lib`
- `pnpm build-all`
- `pnpm test-start-turbo
test/production/app-dir/client-components-tree-shaking/index.test.ts`
- `pnpm test-start-webpack
test/production/app-dir/client-components-tree-shaking/index.test.ts`

<!-- NEXT_JS_LLM -->


<!-- fleet 10716dab-2d36-4687-94ae-cd7bdfeac985 -->

---------

Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
## What?

Extends the export-usage passthrough introduced by #98621 to the
transparent wrappers used for dynamic entries, server components, and
shared server utilities.

The existing reference-tree-shaking production fixture now covers each
wrapper and verifies that unused sibling exports do not remain in
Turbopack's server chunks.

## Why?

These wrappers forward another module's export surface, but previously
marked every target export as used. That kept otherwise unreachable
modules in production output and limited inner-graph tree shaking.

## How?

The dynamic-entry and server-component wrappers now pass their own
resolved export usage to their targets. The custom server-utility
reference reports the same passthrough binding usage while preserving
its shared chunking and merge behavior.

A public Turbopack constructor creates passthrough export-usage values
for references outside `turbopack-core`, consistent with the existing
constructors for other usage modes.

## Verification

- `cargo check -p next-core`
- `pnpm build-all`
- `pnpm test-start-turbo
test/production/app-dir/reference-tree-shaking/reference-tree-shaking.test.ts`
- `pnpm test-start-webpack
test/production/app-dir/reference-tree-shaking/reference-tree-shaking.test.ts`

<!-- NEXT_JS_LLM -->


<!-- fleet df1472be-5cd1-4bd6-9fab-4efc1defa4f9 -->

Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
### What?

Migrates the package CSS side-effects coverage from #70087 into the
current `css-order` end-to-end suite. The matrix covers `sideEffects`
values of `true`, `false`, broad CSS arrays, and global-CSS-only arrays
across App Router, Pages Router, client components, and server
components with client children.

### Why?

The older coverage never reached `canary`, and most of its Turbopack
cases were skipped as inconsistent. Keeping the scenarios in the current
suite verifies that package CSS ordering remains deterministic in both
Turbopack's default chunking mode and the graph chunker.

### How?

The test uses explicit synthetic package fixtures and reuses the suite's
existing Turbopack mode matrix, including the graph string and object
configurations. The packages are transpiled so Pages Router exercises
bundler CSS behavior rather than externalizing CSS imports to Node.
Invalid entrypoints, selectors, routes, and CSS module references from
the old fixtures were corrected during migration.

This does not include the webpack loader implementation change proposed
by #70087.

### Verification

- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/css-order/css-order.test.ts` (189 passed, 114 existing
todos)
- `HEADLESS=true pnpm test-start-turbo
test/e2e/app-dir/css-order/css-order.test.ts` (291 passed, 12 existing
todos)
- `HEADLESS=true pnpm test-start-webpack
test/e2e/app-dir/css-order/css-order.test.ts` (192 passed, 8 existing
todos)

<!-- NEXT_JS_LLM -->

<!-- fleet 10f9743e-de76-437c-8fdc-76b7be42a9b9 -->

---------

Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
Fixes: #98609

Editor note: Ensure this lands well into
#98407 too
@pull pull Bot locked and limited conversation to collaborators Sep 14, 2026
@pull pull Bot added the ⤵️ pull label Sep 14, 2026
@pull
pull Bot merged commit 25fe6f6 into code:canary Sep 14, 2026
1 check 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.

4 participants