[pull] canary from vercel:canary - #1346
Merged
Merged
Conversation
…ion (#97712) ## What - Documents how legacy `prefetch={true}` behavior changes with Partial Prefetching and how to choose the UI worth preserving. - Updates the adoption skill to capture a passing flag-off `instant()` baseline, use the same assertions to drive the migration, and retain them as regression coverage. - Adds a reusable production test rig, keeps additional per-link optimization separate from adoption, and surfaces `prefetch={false}` links that may no longer be needed. - Applies the shared test-rig fixes discovered during dogfooding to the Cache Components optimizer. ## Why Legacy `prefetch={true}` could include uncached dynamic content. With Partial Prefetching, it includes the shared App Shell and cached URL-specific content instead. A passing build or clean insight sweep does not prove that the intended prefetched UI survived the migration, so the skill now records that contract before adoption and verifies it unchanged afterward. The guide presents the same test workflow as an optional programmatic check for manual adopters. ## Testing - Prettier, Alex, and skill frontmatter validation - Dogfooded on v0 in vercel/v0#28842 - Partial Prefetching adoption eval: 6/6 in #97759
## Summary
This adds an experimental `strictRouteMatching` flag that leaves a
matcher out when its finalized loader tree contains a synthesized
default that will always call `notFound()` for a slot actually declared
by the owning layout. Adding a `default.tsx` keeps the matcher, and
structural router-state branches that are not real slots of that layout
do not make it incomplete. The flag defaults to `false` so matcher
pruning can roll out independently from the preceding loader-tree
correction.
The main goal is to make `children` and named slots behave the same way.
If a URL cannot construct a complete route tree on its own, it should be
treated as an unmatched URL instead of sometimes showing a slot 404 and
sometimes producing a missing page or default error.
## Semantics
For example:
```text
app/split-matcher/
├── layout.tsx
├── foo/page.tsx
├── bar/page.tsx
└── @slot/[...parts]/page.tsx
```
With strict route matching disabled, Next.js emits matchers for
`/split-matcher/foo`, `/split-matcher/bar`, and the broad
`/split-matcher/[...parts]`. The broad matcher can match any URL, but
its `children` branch has neither a matching page nor a default, so it
can only construct a permanent 404 tree. With strict route matching
enabled, that broad matcher is omitted while `/foo` and `/bar` remain
because each combines a real `children` page with the named-slot
catchall. Adding `app/split-matcher/default.tsx` deliberately makes the
broad matcher complete and keeps it.
The same rule applies without a catchall:
```text
app/disagreeing-slots/
├── layout.tsx
├── @first/foo/page.tsx
└── @second/bar/page.tsx
```
`/foo` is incomplete because `@second` has no matching page or default,
and `/bar` is incomplete for the corresponding reason in `@first`, so
neither matcher is emitted. A later PR in this stack reports the
now-unreachable page files as a project misconfiguration.
A declared `children` route is treated like any named slot:
```text
app/declared-children/
├── layout.tsx
├── page.tsx
└── @panel/
├── default.tsx
└── details/page.tsx
```
`/declared-children` is complete because `children` uses `page.tsx` and
`@panel` uses its default. `/declared-children/details` is incomplete
because `@panel` matches its page while the declared `children` slot has
no matching page or default at `/details`, so that matcher is pruned.
A route composed entirely from declared named slots is also complete:
```text
app/named-only/
├── layout.tsx
├── @left/[...slug]/page.tsx
└── @right/[...slug]/page.tsx
```
The preceding PR's default-on `explicitParallelRouteChildren` behavior
means this loader tree contains only `left` and `right`. Strict matching
keeps `/named-only/[...slug]` because both declared slots match; it does
not invent `children` and then prune the route for failing to satisfy
that nonexistent slot.
We got here incrementally.
[#47872](#47872) introduced the
404 fallback for unmatched parallel slots,
[#60186](#60186) added a
development warning because this was confusing in practice and linked
[#51805](#51805) and
[#49569](#49569), and
[#84702](#84702) later made a
missing default a build error for named slots while leaving `children`
on the old fallback for backwards compatibility. Strict matching takes
the next step and treats a matcher that can only construct a permanent
404 tree as unmatched.
This changes soft navigations that only worked by preserving a
previously active slot even though the URL could not be loaded directly,
which is why matcher pruning remains behind its own experimental flag.
The interception retention markers backed by `default-null`, including
named host slots from the first PR in this stack, are complete route
patches and are not pruned. This change however is well motivated
because if you did client nav to a route that only matches a named slot
and then hard refresh you will end up getting a 404. This is a sign our
current semantics are actually broken.
If you want to preserve the perma 404 behavior of the
slot-without-default you can just add a default and make it call
`notFound()` unconditionally.
## Verification
- `pnpm build-all`
- Focused `normalize-catchall-routes` unit coverage
- Production and development e2e coverage on Turbopack and Webpack
- The pruning e2e matrix with Cache Components enabled
<!-- NEXT_JS_LLM -->
The class names were unnecessarily long. Use the same as the lightningcss default: `[hash]_[local]` which is `<hash of the full file path>_<original class name or identifier>` Keep the previous longer mechanism to aid in debugging in dev Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
## Summary - mark the deploy-release-test repository skill as internal - prevent public skill discovery and telemetry publication for this repo-only workflow ## Testing - validated the SKILL.md frontmatter parses with metadata.internal set to true - git diff --check Co-authored-by: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com>
When initializing a new project with create-next-app, the interactive prompt will now ask the user if they want to enable Cache Components. For now the option defaults to off. We'll flip the default back on once there's a flow that guides users to the right recommendation based on the kind of site they're building. The option can still be enabled interactively, or with the `--cache-components` flag. If the user chooses to enable Cache Components, the project will also be initialized with Partial Prefetching enabled. There's no separate prompt for Partial Prefetching; the only reason they are separate configs is because Cache Components shipped in 16.0 before Partial Prefetching existed. This is not a breaking change because it does not change any behavior in Next.js itself, only the create-next-app CLI. It has no impact on any existing Next.js projects.
## Summary Builds on #97591. Webpack currently removes most of `.next` on devserver startup. We can remove more as well. This keeps the age-based removal introduced in #97591 and expands it to `traces`, logs, etc. However, for any other directory that is not `cache` or `lock`, completely remove it on startup. This includes types, etc. Apply age-based deletion to Turbopack-owned output that can be restored from cache or recomputed, including route entries, chunks, assets, service workers, middleware, and instrumentation. Completely remove other dev output so logs, traces, generated types, diagnostics, and future framework-owned output cannot be left as mixed generations. Use exact-path exclusion sets in `recursiveDeleteSyncWithAsyncRetries`. The complete pass retains `cache`, `lock`, and Turbopack-owned paths; the age-based pass then sweeps those Turbopack paths. Both passes finish before project creation. ## Verification - `pnpm test-unit test/unit/recursive-delete.test.ts` - `pnpm --filter=next types` --------- Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Will Binns-Smith <755844+wbinnssmith@users.noreply.github.com>
Agent evals, skills, and the eval runner do not affect the framework runtime, but they currently make `Determine changes` schedule the full Rust, native, deployment, and framework test matrices. Classify changes confined to `evals/`, `skills/`, and `run-evals.js` with the existing lightweight documentation path. The always-on build and lint checks still run. Validated with Node syntax checking, Prettier, ESLint, and `git diff --check`.
### What? Upgrade Turbopack's workspace dependencies to DashMap 7.0.0-rc2 and Hashbrown 0.15.4, removing Hashbrown 0.14 from the `turbo-tasks-backend` dependency graph. ### Why? `turbo-tasks-backend` previously compiled two Hashbrown versions because its custom DashMap helpers shared Hashbrown 0.14's private raw table types. Converging the backend graph on Hashbrown 0.15 removes that duplicate backend codegen path and slightly reduces the shipped native addon's size. A clean release A/B of the unstripped x86-64 `next-napi-bindings` cdylib measured: | Revision | `libnext_napi_bindings.so` | | --- | ---: | | canary base `80576037` | 147,824,920 bytes | | PR | 147,818,576 bytes | | **Delta** | **−6,344 bytes (−0.0043%)** | The final gain is small because unrelated SWC dependencies still pull DashMap 6 / Hashbrown 0.14 into the same addon; this change removes only backend-specific Hashbrown 0.14 codegen. Plus... nearly everything is monomorphized anyway ### How? DashMap 7 replaces its Hashbrown 0.14 raw table with Hashbrown 0.15's public `HashTable` API. The backend helpers now use that public API while retaining their existing shard locking and allocation behavior: - heterogeneous cache lookup and insertion still reuse a pre-located shard and precomputed hash; - the entry helper passes Hashbrown's native `hash_table::Entry` into a closure, preserving precise lock-release timing without a custom self-referential entry type or cloned hasher; - nonblocking removal still avoids lock-order deadlocks; - two-key mutation uses a release-mode disjointness assertion followed by `get_many_unchecked_mut` to avoid a redundant duplicate-pointer scan; - snapshot draining still transfers ownership of each shard table and releases task memory incrementally; - custom mutable guards remain non-`Send`. The migration also replaces several raw-pointer iteration and removal paths with safe `HashTable` operations. Existing raw-entry users in `auto-hash-map` and `turbopack-trace-server` explicitly enable Hashbrown 0.15's compatibility feature. ### Performance Performance testing with the overhead.rs benchmark revealed no regression/progression <!-- NEXT_JS_LLM --> <!-- fleet 53ff0bed-46a9-4361-befa-a1791d585f27 --> --------- Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
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 : )