[pull] canary from vercel:canary#1031
Merged
Merged
Conversation
### 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )