Skip to content

[pull] canary from vercel:canary#1082

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

[pull] canary from vercel:canary#1082
pull[bot] merged 10 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

@pull pull Bot commented May 28, 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 : )

lubieowoce and others added 8 commits May 28, 2026 13:31
The tests in
`test/development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts`
seem to be failing a lot. According to
[datadog](https://app.datadoghq.com/ci/test/flaky?query=%40test.name%3Ainstant-nav-panel%2A&sort=-pipelines_failed&viewMode=flaky),
the worst offender fails 40% of runs.
<img width="762" height="458" alt="Screenshot 2026-05-28 at 14 58 46"
src="https://github.com/user-attachments/assets/148b8122-e5d4-407c-89cf-12101297f189"
/>
I'm disabling them to avoid disrupting people's CI runs too much

I'm taking a stab at unflaking them here
#94171, but no luck so far
In both the use-sites of `prependIsPartialByte` we actually have all the
stream chunks available as an array, so we can avoid making a whole
TransformStream. This was especially unnecessary in the static prerender
codepath, where we'd turn the chunks into a stream, transform the
stream, and immediately `streamToBuffer` it right after.
This test has been flaking in weird ways, but i also noticed that it's a
bit broken
- we were running build twice, because `next.start()` does that. this
affected what was in the logs that we assert on
- The assertion on the route was incorrect (it checked for `[page]
/static/route` instead of `[route] /static/route`, which would never be
emitted)
- ...which was hiding the fact that actually the thing *was* getting
logged due to a bug unrelated to after()

The idea in the test was essentially to assert that no after()s run at
runtime if the page/route is statically prerendered (which implicitly
also asserts that `after` itself does not make it dynamic). But it
appears that returning a `new Response()` from a static handler is
unsupported (bug imho) because it logs `Failed to update prerender cache
for /static/route Error: LRUCache: calculateSize returned 0, but size
must be > 0. Items with size 0 would never be evicted, causing unbounded
cache growth.`. As a workaround, i just gave it a non-empty body

I don't know if this will fix the flakes we've been seeing in CI. Those,
bizarrely, fail here
```
Error: can not run export while server is running, use next.stop() first
    at NextStartInstance.build (/__w/next.js/next.js/test/lib/next-modes/next-start.ts:255:13)
    at Object.build (/__w/next.js/next.js/test/e2e/app-dir/next-after-app-static/build-time/build-time.test.ts:36:36)
 ```
 https://github.com/vercel/next.js/blob/1bc1da711cd0699b620716b204b480485274ff05/test/e2e/app-dir/next-after-app-static/build-time/build-time.test.ts#L36
 
 We do `skipStart` in `nextTestSetup`, and there's no other tests running, so i have no idea what "running server" that error is referring to
### What?

Propagate edge runtime preferredRegion metadata into adapter outputs and
add adapter-config coverage for an edge app route.

### Why?

Adapters need access to preferred region metadata from edge outputs when
generating provider-specific deployment output.

### How?

Copy edge function regions into output.config.preferredRegion and assert
the adapter build-complete output for a fixture route with
preferredRegion set to cdg1.

### Verification

- `pnpm --filter=next build`
- `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-start-webpack
test/production/adapter-config/adapter-config.test.ts`

<!-- NEXT_JS_LLM_PR -->
Previously we pinned all of these to their current versions at the time.
That meant that some of these got pinned to really old versions. This
updates all of the "first-party" `actions/*` dependencies.

Prompted claude with:

```
For all of these uses of actions/*, make sure we're pulling in the latest stable version (check the gh cli). When upgrading across major versions, fetch the release notes from the GH releases using the gh CLI and make sure that there are no problems that the upgrade will cause.
```

Claude read all the release notes and seems to think these upgrades are
safe.

![Screenshot 2026-05-27 at
3.36.15 PM.png](https://app.graphite.com/user-attachments/assets/4b863905-a983-43a1-ba3d-5d3cc2988bc2.png)
This consolidates the two Resume Data Caches into a single discriminated
union and reverts three non-load-bearing changes from #88556. The result
sets up a follow-up that fixes a bug where pages exporting
`unstable_instant = false` cause their `'use cache'` reads to be
incorrectly treated as dynamic.

The cache wrapper short-circuits a `'use cache'` miss to a dynamic hole
when prerendering a fallback shell that was seeded with a read-only RDC
from an earlier phase. The reasoning is that the seed was filled by a
phase-1 prerender of a more-specific sibling route, so a miss in phase-2
means the cache key depends on a fallback param. In PR #79743, we set up
an XOR on the work unit store that directly encoded this distinction: a
prerender carried either a mutable `PrerenderResumeDataCache` (a phase-1
prerender filling caches as it runs) or an immutable
`RenderResumeDataCache` (a phase-2 fallback shell reading from a
phase-1-seeded cache), never both. The bail-out didn't use that signal
directly, though; it was gated on `workUnitStore.allowEmptyStaticShell`,
which at the time happened to coincide with "we have a read-only seed"
because the fallback-shell flow was the only thing setting it. #89077
later widened that flag to also cover `unstable_instant = false`, which
has no seed, so the bail-out started firing for routes that should be
allowed to fill their caches normally. #88556 broke the XOR by carrying
both caches at the same time. In a follow-up, the flag check is replaced
with a precise `workUnitStore.resumeDataCache?.mutable === false`, which
only lands cleanly once the XOR is back.

The three reverts: (1) at the start of the Cache Components branch of
`prerenderToStream`, phase-2 no longer creates a fresh mutable RDC
alongside the prefilled one — it just uses the seed; (2) the swap
between the prospective and final prerender passes that replaced the
prefilled RDC with a freeze of the (now-gone) mutable one is removed, so
the final pass reads from the same seed as the prospective pass; (3) the
line in the cache wrapper that mirrored prefilled-RDC hits into the
mutable RDC (only useful to feed the swap) is removed. The actual fix
from #88556 — selecting the seed RDC by matching known params,
`buildRDCCacheByPage` in `export/index.ts` — is kept, and the
`ppr-root-param-fallback` test suite that was added in that PR still
passes.

On top of the revert, the two RDC types now carry a `mutable: true |
false` discriminator, the store fields collapse into one
`resumeDataCache: ResumeDataCache | null`, and the specialized
`getPrerenderResumeDataCache` / `getRenderResumeDataCache` helpers are
replaced by a single `getResumeDataCache` returning the union. Call
sites narrow via `resumeDataCache?.mutable` directly, and the typing-lie
in the old `getRenderResumeDataCache` (coercing a mutable cache to
read-only via spread) is gone. Restoring the XOR as two separate fields
would have worked, but the discriminated union makes the invariant
compiler-enforced and removes a typing-lie that the original design
already carried — and the revert touches the same call sites anyway, so
bundling the refactor in one pass was cleaner than splitting it.
This fixes a bug where pages exporting `unstable_instant = false` cause
their `'use cache'` reads to be incorrectly treated as dynamic, so the
build emits an empty static shell where it should contain the cached
content.

The root cause sits in the cache wrapper's Resume Data Cache (RDC) miss
bail-out. When prerendering a fallback shell whose RDC is the prefilled,
read-only seed from a phase-1 prerender of a more-specific sibling
route, a `'use cache'` miss is short-circuited to a dynamic hole — under
that contract a miss means the cache key depends on a fallback param.
That bail was gated on `workUnitStore.allowEmptyStaticShell`, which
originally coincided with "we have a read-only seed" because the
fallback-shell flow was the only thing setting the flag. #89077 widened
the flag to also cover `unstable_instant = false`, which has no seed, so
the bail started firing for routes that should be allowed to fill their
caches normally.

To fix this, we're replacing the proxy condition with the structural
check `workUnitStore.resumeDataCache?.mutable === false`, which
precisely matches the case the bail is for: a prerender whose RDC is the
immutable, prefilled seed. This avoids the false positive for when
`unstable_instant = false` is set and we're doing a prospective
prerender with an empty mutable RDC. The check is type-narrowed via the
discriminated union introduced in #94194, which is why that PR landed
first. With the cache wrapper no longer the consumer,
`workUnitStore.allowEmptyStaticShell` is removed from the prerender
store — the flag survives only as `renderOpts.allowEmptyStaticShell` and
a local parameter feeding the "shell may be empty for any reason" check
in `dynamic-rendering.ts`.
- [x] skip traced edges properly in all graph traversals
- [x] iter_nodes and enumerate_nodes include the traced modules
    - [x] Don't propagate is_self_async inside of traced references as a perf optimization
- [x] fix performance
- [x] validate that NFT JSON files are identical
- [x] ~~validate/adjust bundle analyzer output~~ will be in followup
- [x] audit `fn chunking_type()` changes

Benchmark:
```
* ced85b3 - (2 weeks ago) refactor - Niklas Mischkulnig (HEAD -> mischnic/nft-module-graph, origin/mischnic/nft-module-graph)

TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build   334.96s user 44.57s system 788% cpu 48.152 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build   343.39s user 42.61s system 809% cpu 47.659 total

* 5edf482 - (77 minutes ago) v16.3.0-canary.32 - next-js-bot[bot] (HEAD, tag: v16.3.0-canary.32)

TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build   333.42s user 43.57s system 712% cpu 52.877 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build   332.95s user 43.15s system 791% cpu 47.515 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build   337.59s user 41.28s system 771% cpu 49.117 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build   335.25s user 45.53s system 718% cpu 52.975 total
```

<details>
<summary>Previous benchmarks</summary>

```
5221241 mischnic/nft-module-graph

pnpm next build   371.41s user 66.39s system 737% cpu 59.353 total
pnpm next build   380.13s user 59.62s system 751% cpu 58.548 total
pnpm next build   374.25s user 60.55s system 761% cpu 57.102 total

8e4cfc5 canary

pnpm next build   370.77s user 53.89s system 762% cpu 55.725 total
pnpm next build   383.16s user 55.61s system 744% cpu 58.921 total
pnpm next build   382.34s user 53.51s system 757% cpu 57.512 total
pnpm next build   381.15s user 54.50s system 751% cpu 57.943 total
```


```
b0d5411a79 mischnic/nft-module-graph
pnpm next build --experimental-build-mode=compil  368.75s user 62.05s system 749% cpu 57.445 total
pnpm next build --experimental-build-mode=compil  368.95s user 58.42s system 763% cpu 56.004 total

0e3ad27 mischnic/nft-module-graph
pnpm next build --experimental-build-mode=compil  369.48s user 60.62s system 748% cpu 57.494 total
pnpm next build --experimental-build-mode=compil  374.89s user 52.27s system 730% cpu 58.449 total
pnpm next build --experimental-build-mode=compil  375.02s user 52.89s system 747% cpu 57.274 total

f37073e mischnic/speed-next-dynamic-map
pnpm next build --experimental-build-mode=compil  389.58s user 55.98s system 704% cpu 1:03.21 total

e599b11 mischnic/fix-side-effect-edge-removal
pnpm next build --experimental-build-mode=compil  386.60s user 53.34s system 720% cpu 1:01.09 total

f68f70b canary
pnpm next build --experimental-build-mode=compil  387.46s user 53.72s system 738% cpu 59.716 total
pnpm next build --experimental-build-mode=compil  390.33s user 53.54s system 734% cpu 1:00.43 total
pnpm next build --experimental-build-mode=compil  385.33s user 56.55s system 722% cpu 1:01.18 total
pnpm next build --experimental-build-mode=compil  386.49s user 56.44s system 726% cpu 1:00.96 total
```



```
b1ed455 origin/mischnic/nft-module-graph
pnpm next build --experimental-build-mode=compile  467.28s user 75.24s system 791% cpu 1:08.56 total
pnpm next build --experimental-build-mode=compile  465.00s user 76.80s system 831% cpu 1:05.20 total
pnpm next build --experimental-build-mode=compile  473.86s user 70.73s system 790% cpu 1:08.90 total

3cb77c8 canary
pnpm next build --experimental-build-mode=compile  367.91s user 58.06s system 726% cpu 58.672 total
pnpm next build --experimental-build-mode=compile  362.97s user 57.68s system 746% cpu 56.379 total
pnpm next build --experimental-build-mode=compile  364.59s user 57.01s system 724% cpu 58.167 total
```

</details>
@pull pull Bot locked and limited conversation to collaborators May 28, 2026
@pull pull Bot added the ⤵️ pull label May 28, 2026
sampoder and others added 2 commits May 28, 2026 12:41
#94186)

Promises are not included in the list of JavaScript's falsy values,
therefore, they are always truthy. See
https://developer.mozilla.org/en-US/docs/Glossary/Truthy. Additionally,
promises are neither `null` or `undefined` so they are not nullish:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing.

This PR updates Turbopack's analyzer to reflect this + adds unit tests
for `is_truthy` and `is_nullish`.
@pull pull Bot merged commit 4fb8142 into code:canary May 29, 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.

6 participants