Skip to content

[pull] canary from vercel:canary#1063

Merged
pull[bot] merged 9 commits into
code:canaryfrom
vercel:canary
May 21, 2026
Merged

[pull] canary from vercel:canary#1063
pull[bot] merged 9 commits into
code:canaryfrom
vercel:canary

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 21, 2026

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 : )

mischnic and others added 9 commits May 20, 2026 21:29
I set it to `::Unknown` because we the runtime may or may not support
module-sync. So let's just trace both for now



There is one problem though:


https://nodejs.org/docs/latest-v26.x/api/packages.html#conditional-exports
> "module-sync" - matches no matter the package is loaded via import,
import() or require(). The format is expected to be ES modules that does
not contain top-level await in its module graph - if it does,
ERR_REQUIRE_ASYNC_MODULE will be thrown when the module is require()-ed.

So we have multiple options:
1. We definitely want to respect module-sync for tracing. We don't
really have to throw ERR_REQUIRE_ASYNC_MODULE here, Node.js will do it
at runtime anyway.
2. ~~What about bundling? Either~~
- ~~Respect module-sync always, but don't throw
ERR_REQUIRE_ASYNC_MODULE.~~
- ~~Respect module-sync always, and do throw a build error the module
requires TLA. This would require a separate validation pass though.~~
   - I'm not enabling it for bundling for now
## Summary

Memoize passing tests across attempts of the same workflow run, so a
re-attempt after a timeout or cancellation can skip what already passed.


## What changed

- `run-tests.js` appends each passing test's filename to
`$NEXT_TEST_PASSED_FILE` as it finishes (sync `write` + `fsync`, fd kept
open across calls). On startup it reads the same file and skips any
entries that match.
- `build_reusable.yml` wraps the test step with `actions/cache/restore`
(before) and `actions/cache/save` (after, with `if: always()`). The save
step runs on success, failure, and cancel — which is the whole point: a
cancelled attempt still gets to preserve its progress for retry.
- Cache key is scoped to
`${input_step_key}-${run_id}-attempt${run_attempt}`, with `restore-keys`
falling back to any earlier attempt of the same run.

The previous implementation wrote a single Turbo-remote-cache blob
*after* `Promise.allSettled` resolved — so a cancellation (like [run
26127371192](https://github.com/vercel/next.js/actions/runs/26127371192/job/76845288867))
lost every passed test from that attempt.

This also removes one dependency on the turbo-remote cache (there are
still two more uses of `scripts/turbo-cache.mjs`)

<!-- NEXT_JS_LLM_PR -->
A few changes to devlow-bench so the comparison output is easier to read
and so a couple of flaky page-load runs don't quietly poison the stats.

**compare**
- Show p50 / p90 / p99 instead of mean / p50 / p90, with Δ p50 and a
single Mann–Whitney p-value (Welch's t-test and Δ mean are gone — the
mean was dragging on bad runs).
- Hoist the modal sample count into an `n = 7 per metric` banner so only
the outlier rows carry `(n)`.

**runner**
- Each attempt's measurements are buffered locally and only merged on
success. Failed runs are retried (capped at 2× warmup+n) until we have a
clean n samples.
- Per-variant retry line plus an end-of-run summary noting which
variants recovered and which fell short.

**browser**
- `hardNavigation` / `reload` now throw when the navigation response is
missing or non-2xx. Previously a `200`-committed-but-broken page was
being recorded as a real sample.

The trigger was a run where 2 of 7 cold-build attempts hit an error
page, dragging the mean response size from 45 MB to 33 MB while the p50
was unchanged.

<!-- NEXT_JS_LLM_PR -->
Version bump so we can publish the changes from #93950 (and the
previously-unpublished 0.3.5 work) to npm.

Stacked on top of #93950.

<!-- NEXT_JS_LLM_PR -->
The body of `if (cacheComponents)` in `prerenderToStream` is extracted
into a local helper, `prerenderWithCacheComponents(getPayload)`. The
catch-block error paths now route through that helper whenever Cache
Components is enabled, which means the legacy `prerender-legacy` store
is no longer reachable from a Cache Components prerender.

As a result, `notFound()`, `forbidden()`, and `unauthorized()` recovery
renders the matching fallback boundary under `prerender` and
`prerender-client` semantics. Dynamic API access in those boundaries —
for example `useSearchParams()` without a surrounding `<Suspense>` — now
surfaces as a blocking-route error instead of the legacy
`BailoutToCSRError`.

The dev side will be handled in a follow-up. The prerender handling
diverged a bit from the dev rendering in #92231, and we'll likely need
to re-align the dev rendering first.

> [!TIP]
> Best reviewed with hidden whitespace changes.
Plumbing for upcoming App Shell prefetching support: sets up the config
field, the zod entry, and the build-time `process.env.__NEXT_APP_SHELLS`
define. No behavior change in this PR — nothing reads the flag yet.
Subsequent PRs in this sequence wire the server- and client-side work
behind it.

Enabling `experimental.appShells` requires several adjacent flags to
also be enabled: `cacheComponents`, `experimental.prefetchInlining`,
`experimental.varyParams`, `experimental.optimisticRouting`, and
`experimental.cachedNavigations`. All of these are on track to become
defaults soon, so there's no value in supporting App Shells against
arbitrary subsets — the validation enforces that App Shells is tested in
the configuration it will ship with. Each requirement drops out as the
corresponding flag becomes a default.
<!-- NEXT_JS_LLM_PR -->
…that overrides `std::thread::available_parallelism` callsites (#93995)

We want to use this to potentially improve efficiency in e2e tests where
we're running many instances of Turbopack at once. By default,
turbo-tasks will try to use every available CPU core.

**This environment variable does not strictly limit Turbopack to using 4
cores, it just restricts the number of main tokio worker threads and
changes how we shard dashmaps.**

This option will not make sense for the vast majority of users, it only
makes sense when you are running *many* instances of Turbopack at once,
and the exact semantics are potentially confusing, as it is not a hard
limit.

## Test Plan

Build vercel-site with this set to 1 and see a little over 100% CPU
usage. Set it to 8 and see around 800% CPU usage.

```
TURBO_TASKS_AVAILABLE_PARALLELISM=1 pnpm next build --experimental-build-mode=compile
```
@pull pull Bot locked and limited conversation to collaborators May 21, 2026
@pull pull Bot added the ⤵️ pull label May 21, 2026
@pull pull Bot merged commit 80cb344 into code:canary May 21, 2026
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.

6 participants