Skip to content

[pull] canary from vercel:canary#1031

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

[pull] canary from vercel:canary#1031
pull[bot] merged 4 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

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

lukesandberg and others added 4 commits May 7, 2026 17:05
### What?

Replaces the `rcstr!` macro in `turbo-rcstr` with a proc-macro
implementation in a new `turbo-rcstr-macros` crate. The proc macro
inspects the literal at expansion time and emits only the relevant arm —
no dead `else` branch.

### Why?

The previous `macro_rules!` macro emitted both an inline arm and a
static + `inventory::submit!` arm at every call site, expecting `const`
evaluation to discard one. `inventory::submit!` adds `#[used]` to its
constructor, so the dead arm shipped in the binary even when const eval
determined the live arm was the inline one.

Across the workspace there are ~852 inlinable `rcstr!` literals (≤ 7
bytes); each previously emitted a wasted `PrehashedString` static, an
inventory node, and a startup `ctor`.

### How?

A `#[proc_macro] rcstr` in the new `turbo-rcstr-macros` crate decides at
expansion time:

- inlinable literal → `inline_atom(lit).unwrap()`. No static, no
inventory entry, no dead branch.
- non-inlinable literal → static + `inventory::submit!` + `from_static`,
no inline arm.
- constant identifiers / `concat!(…)` / non-literal inputs → fall back
to the original both-branches expansion so const eval picks the arm. ~11
such call sites.

`turbo-rcstr`'s `atom_size_64` / `atom_size_128` features forward to the
proc-macro crate so the threshold is exact for every build configuration
without a runtime const branch.

The proc macro deliberately avoids `syn`, `quote`, and `proc-macro2`. It
pattern-matches on `proc_macro::TokenTree` directly, asks the compiler
for the literal's unescaped value via `Literal::str_value` (gated on the
unstable `proc_macro_value` feature), and emits the chosen expansion by
parsing a string template via `TokenStream::from_str`. The proc-macro
crate compiles in ~0.7 s with zero third-party dependencies.

### Compile time

Clean rebuild of `turbopack-core` in release mode (143 `rcstr!` call
sites). Dependencies cached; only `turbopack-core` itself rebuilt each
iteration. `darwin-aarch64`.

|                    |   n | min      | mean     | median   | stdev    |
| ------------------ | ---:| --------:| --------:| --------:| --------:|
| canary             | 7   | 27.11 s  | 28.00 s  | 28.12 s  | 0.61 s   |
| `rcstr_inventory`  | 7   | 26.60 s  | 27.99 s  | 27.96 s  | 0.80 s   |
| **delta** | | | **−0.01 s (−0.06 %)** | −0.16 s | |

Within noise. The proc-macro per-invocation overhead is offset by
reduced emitted-token volume (~40 % less code across all `rcstr!` sites
— the 852 inlinable literals collapse from ~80 tokens to ~6 tokens
each), so the compiler does materially less parsing and type-checking on
the macro output.

### Binary size

Release build of `next-napi-bindings` cdylib on `darwin-aarch64`:

| | canary | `rcstr_inventory` | delta |
| ---------------------------- | ------------------------------- |
------------------------------- | ------------------------------ |
| Release `.dylib` (raw) | 123,699,312 B (117.97 MiB) | 123,349,424 B
(117.64 MiB) | **−349,888 B (−0.28 %)** |
| Stripped (`strip -x`) | 83,502,264 B (79.63 MiB) | 83,434,984 B (79.57
MiB) | **−67,280 B (−0.08 %)** |
| Stripped + `gzip -9` | 28,967,762 B (27.63 MiB) | 28,958,198 B (27.62
MiB) | **−9,564 B (−0.03 %)** |

The raw release build shrinks by ~342 KiB — the 852 dead `static
PrehashedString` + inventory node + ctor entries no longer being emitted
for inlinable call sites. Most of that compresses well (dead data is
stripped and gzip handles the rest), so the user-facing impact in the
gzipped npm tarball is ~9 KiB.

<!-- NEXT_JS_LLM_PR -->
## What?

The Turbopack path incorrectly included a double backslash instead of
one backslash in the regex matcher.
## What?

Applies
d166096
for canary and handles the Turbopack-side implementation for
`middleware-manifest.json` which is used for edge runtime middleware.ts

---------

Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
#93549)

Under `experimental.varyParams`, when a page reads `searchParams` from a
URL without a query string, `createVaryingSearchParams` previously
returned a plain object whose only own properties were getters for keys
that already existed in the URL. With no keys present, that's an empty
`{}` — so `Object.entries`, spread, `in` checks, and missing-key reads
(e.g. `searchParams.foo` returning `undefined`) all silently no-opped
without registering an access. The segment ended up keyed at the
`Fallback` search slot in the segment cache, where it shadowed
subsequent prefetches with non-empty search params via `Fallback`
resolution, silently serving the stale empty-query cache entry on
navigation.

This switches the implementation to a `Proxy` with `get`, `has`, and
`ownKeys` traps that record the `'?'` sentinel on every string access.
Search params have no fixed schema, so any access — including
missing-key reads, `in` checks, and enumeration — must register as
varying. The `get` trap has one carve-out: `.then` reads are skipped
when no `then` key exists on the target, since `Promise.resolve` and
React Flight probe `.then` to test thenability and those probes
shouldn't count as user dependencies. As a trade-off, a page that reads
`searchParams.then` to compute its output and is prefetched without a
`then` key won't register the access — accepted because `then` is
reserved by the Promise protocol and essentially never used as a query
parameter name.

The added regression test prefetches the no-query URL first and asserts
that a subsequent `?foo=1` prefetch still triggers a fresh request.
Without the fix the lookup resolves to the empty-query cache entry
through `Fallback`, no request is initiated, and the test times out
waiting for one.
@pull pull Bot locked and limited conversation to collaborators May 7, 2026
@pull pull Bot added the ⤵️ pull label May 7, 2026
@pull pull Bot merged commit de37cd7 into code:canary May 7, 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.

3 participants