Skip to content

[pull] canary from vercel:canary#1098

Merged
pull[bot] merged 8 commits into
code:canaryfrom
vercel:canary
Jun 4, 2026
Merged

[pull] canary from vercel:canary#1098
pull[bot] merged 8 commits into
code:canaryfrom
vercel:canary

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Jun 4, 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 : )

lubieowoce and others added 8 commits June 3, 2026 19:40
Introduces new shell stages and adds relevant tasks where needed. We're
not changing the timing of when anything resolves yet, so this should
not have any behavioral changes.
…cs slugs (#94017)

### What?

Adds "Copy prompt" button to all 33 instant-guidance fix cards. Updates
card links, factory `Learn more:` URLs, and overlay routing to the new
docs slugs. Adds `[group]` tag prefix to CLI fix bullets so agents can
map them back to card prompts.

### Why?

Cards tell developers _what_ to do. The button gives agents a
ready-to-paste instruction. The `[group]` tag lets agents reading CLI
output find the matching card in the docs without parsing prose.

### How?

- `prompt` field on all 33 `FixCard` entries.
- Button replaces the external-link icon in the top-right; link moves
next to the label.
- Card links updated to `blocking-prerender-*` and
`instant-unrendered-segment` slugs (avoids overriding upstream pages).
- Variant-aware URL routing for `metadata` and `viewport` (matches
existing `blocking-route` pattern). `InstantHeaderExplanation` takes a
`variant` prop.
- Fix bullets prefixed with their card group: `[cache]`, `[stream]`,
`[block]`, etc. Tags match `<FixOption group>` in the MDX docs.
- CLI bullets use `unstable_instant = false` (the current API). Overlay
cards keep `instant` (aspirational).
- Metadata dynamic-marker bullet now mentions the Suspense wrapper.
- Merged canary: unrendered-segment errors land in the Insights tab via
`isInstantNavigationError`.

### Depends on

- [vercel/front#71640](vercel/front#71640) — 6
sync-IO pages
- [vercel/front#71781](vercel/front#71781) — 4
metadata/viewport pages + `instant-unrendered-segment`
…#94296)

This PR implements `BumpVec` this is a custom vector implementation that
takes in a `Bump` as a type (from bumpalo) so that we get `Send`/`Sync`
on our `JSValue` vectors when we make that switch in:
#94297.
Reimplements app shells in runtime prefetches in terms of a staged
render.

when `appShells` is on:
- a `next-router-prefetch: 2` request (i.e. "including link data") will
have a shell stage that only includes session data. we communicate the
byte offset to the client so it can rewind the response to a session
fallback
- a `next-router-prefetch: 3` request (i.e. "session shell") stops
rendering after the shell stages, i.e. link data is never resolved. this
replaces the previous `forceOmitParams` implementation.
 
Note that In order to produce a session shell, we have to resolve static
`params` and rootParams in the Runtime stage (previously, they'd resolve
in the static stage). This is because params are link data and cannot be
part of the session shell. We don't really need to rewind a runtime
prefetch to a static stage, so this divergence in behavior shouldn't be
meaningfully observable.

Notable call-out: root params getters can also be called inside caches.
if a cache accesses root params, then the cache depends on link data and
must be excluded from the shell. We rely on existing mechanisms for
tracking root param access and delay the cache appropriately in the
final render.
# What

Replace the `derive` macros for TaskInput with a proc macro
`[turbo_tasks::task_input]` (and analogous support inside of the
`turbo_tasks::value` macro.

Introduce a hand written `CloneResolved` future type for TaskInput
implementations that are always resolved.

# Why

This allows us to take advantage of the `NonLocalValue` marker trait. If
a type is `NonLocalValue` then `TaskInput` can have trivial
`is_resolved` and `resolve_input` implementations. This applies to the
vast majority of TaskInputs but the current `derive` implementation
always produces a recursive `async` `resolve_input` implementation but
it is rarely needed and rustc/llvm do a bad job of optimizing it.

## Code-size impact

`next-swc.darwin-arm64.node` — release profile, `pnpm swc-build-native
--release`, macOS aarch64.

| Metric | canary | this branch | Δ bytes | Δ % |
| --- | ---: | ---: | ---: | ---: |
| Raw `.node` | 124,494,592 | 124,217,280 | −277,312 | −0.22% |
| Stripped (`strip -x`) | 84,294,000 | 84,013,136 | −280,864 | −0.33% |
| Stripped + gzip -9 | 29,123,538 | 28,898,920 | −224,618 | −0.77% |

## Performance

A similar measurement of performance was neutral

| Metric | canary | temporary | Δ | % |
|---|---|---|---|---|
| wall time (s) | 42.659 ± 1.851 | 42.501 ± 2.028 | −0.158 | −0.4% |
| user time (s) | 294.322 ± 1.834 | 293.207 ± 2.070 | −1.115 | −0.4% |
| sys time (s) | 74.158 ± 4.197 | 73.543 ± 5.725 | −0.615 | −0.8% |
| MaxRSS (MB) | 13650.1 ± 66.0 | 13610.1 ± 57.5 | −40.0 | −0.3% |

All deltas are smaller than one standard deviation — statistically
indistinguishable from noise on this benchmark, as expected for a small
optimization.
## What

Removes the `ArgMeta::is_resolved` function-pointer field and the 592
monomorphized `closure#3` trampolines it generated. The
`TaskInput::is_resolved` check that runs on the synchronous fast path of
every turbo-tasks function call now happens at the macro-generated
callsite on the concrete tuple type, before erasure into `&dyn
StackDynTaskInputs`. For trait calls with `filter_owned`, the check is
fused into the filter functor so the filter and the resolved-check
monomorphize together.

## Why

The `is_resolved` method is almost always trivial after optimization but
putting it behind an opaque function pointer means we always pay a small
code size and perf cost. Inlining actually saves bothr `Vc` field.

Bonus rename: `OwnedStackDynTaskInputs` → `BoxedDynTaskInputs`. The
\"Stack\" was the trait, not the storage — the inner value is a `Box<dyn
DynTaskInputs>` on the heap.

## Hot-path microcheck

The synchronous wrapper for a representative 6-input turbo function
(`directory_tree_to_loader_tree`) now performs the entire `is_resolved`
check as ~15 register-only ARM instructions inlined into the caller —
three `cmp/csel/tbnz` chains testing the discriminant byte of each
`Vc<...>` input. The four trivially-resolved inputs (`FileSystemPath`,
`RcStr`, `AppPage`, `AppPath`) contribute zero instructions because
their `is_resolved` constant-folded to `true`. No indirect call, no
downcast trampoline.

## Code-size impact

Release `next-swc.darwin-arm64.node`, macOS aarch64, vs the `temporary`
branch this PR is stacked on:

| Metric | prior (temporary) | this PR | Δ bytes | Δ % |
| --- | ---: | ---: | ---: | ---: |
| Raw `.node` | 124,217,280 | 123,845,712 | −371,568 | −0.30% |
| Stripped (`strip -x`) | 84,013,136 | 83,880,384 | −132,752 | −0.16% |
| Stripped + gzip -9 | 28,898,920 | 28,887,624 | −11,296 | −0.04% |




<!-- NEXT_JS_LLM_PR -->
@pull pull Bot locked and limited conversation to collaborators Jun 4, 2026
@pull pull Bot added the ⤵️ pull label Jun 4, 2026
@pull pull Bot merged commit f491bdf into code:canary Jun 4, 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.

5 participants