[pull] canary from vercel:canary#1035
Merged
Merged
Conversation
…93612) ### What? Add `.next/package.json` (the distDir commonjs boundary marker) to the `required-server-files.json` manifest. ### Why? `next build` writes `.next/package.json` with `{"type": "commonjs"}` so that everything in `.next/**` is loaded as CJS even when the user's project `package.json` has `"type": "module"`. Without that file, Node walks up to the project `package.json` when loading `.next/server/**/*.js` and tries to evaluate the compiled server bundles as ESM, which fails at runtime. This file is necessary on disk in every server deployment artifact (the standalone bundle, every adapter Node function), but it was not declared in `required-server-files.json`. As a result, adapters consuming `requiredServerFiles.files` did not include the boundary file. `.next/package.json` is conceptually a required server file: any deployment that wants to run `.next/server/**/*.js` correctly under a `"type": "module"` project must ship it. Declaring it in the manifest is the right place to express that contract once for every consumer. This error case would only happen if the project package.json gets included into the Node.js functions. For example when file tracing analysis (node-file-trace) decides it needs to include it (i.e. glob patterns or such). ### How? Add `'package.json'` to the `requiredServerFilesManifest.files` array in `packages/next/src/build/index.ts`. Every entry in that array is joined with `config.distDir`, so this resolves to `.next/package.json`. Both existing consumers pick it up automatically with no further changes: - `packages/next/src/build/adapter/build-complete.ts` iterates `requiredServerFiles` into `sharedNodeAssets`, which is merged into every Node function's `output.assets` regardless of bundler. The Vercel adapter (and any other adapter) gets the file for free. - `copyTracedFiles` in `packages/next/src/build/utils.ts` iterates `requiredServerFiles.files` and copies each entry into `.next/standalone/<relative>`, so the standalone output now contains `.next/standalone/.next/package.json`. ### Tests - `test/production/required-server-files-package-boundary/` — a focused, non-standalone test that builds a `"type": "module"` app and asserts: - `.next/package.json` is `{"type": "commonjs"}` on disk - `.next/required-server-files.json` lists `.next/package.json` - `test/production/standalone-mode/type-module/` — extended with a `pages/dynamic.js` that uses `getServerSideProps`. The test now: - Asserts `.next/standalone/.next/package.json` exists with `{"type": "commonjs"}` - Boots the standalone `server.js` and fetches `/dynamic`, which forces Node to actually evaluate `.next/server/pages/dynamic.js` at runtime — the exact code path the boundary file makes work
We were already pinning nearly all of our third-party GitHub actions, but this also pins our first-party ones (things starting with `actions/*`. This gets us closer to being able to enforcing pinning at the repository level:  The one remaining blocker is this self-reference in a `pull_request_target` action: https://github.com/vercel/next.js/blob/c06d94ba22d0156e8bff28c81f7874b73d80ed03/.github/workflows/pull_request_auto_label.yml#L65 I'm still figuring out the best approach to do there, and I'll submit that in a separate PR. Discussion here about enforcing this org-wide: https://vercel.slack.com/archives/C0AM84PRSGL/p1778110550384279
When we can't validate the entire render because some expected slot wasn't rendered we report that as an error. However we do this before checking if there were errors to report from the slots the did render. Since conditional rendering is a thing and it might inadvertantly cause you to not see more directly actional feedback we now prioritize reported errors from the validation before reporting any unrendered slots
## Remove ineffective turbo-tasks
Identifies and removes turbo-tasks functions where the task overhead exceeds the value they provide. Each turbo-task carries ~4-6μs execution overhead per miss and ~200-500ns per cache hit, plus allocations and bookkeeping.
### What?
Removes 22 `#[turbo_tasks::function]` implementations across resolve plugins, chunk items, and resolve-result helpers — converting them to plain methods or inlining their work. Changes fall into a few buckets:
- **ResolvePlugin condition handling** (`AfterResolvePluginCondition::matches`, `BeforeResolvePluginCondition::matches`, `after_resolve_condition`, `before_resolve_condition`): conditions now store the resolved `Glob` as a `ReadRef<Glob>` on the plugin struct at construction, so `matches` is a pure sync function and the per-plugin `*_resolve_condition` getters are trivial field reads (no longer turbo-tasks). The `after_resolve` / `before_resolve` hooks themselves stay as `#[turbo_tasks::function]` — they synthesize virtual sources/modules and need memoization on `(self, lookup_path, reference_type, request)` to avoid distinct cells producing duplicate module-graph idents.
- The basic theory here is that the right level of caching is at `resolve` and at the hook bodies themselves, not the conditions or condition getters.
- `AfterResolvePluginCondition` and `BeforeResolvePluginCondition` are marked `serialization = "none"` because `ReadRef` cannot be persisted; plugin construction is cheap enough to re-derive on restore.
- **ChunkItem trait methods** (`chunking_context`, `ty`, `content_with_async_module_info`): returned constants or simple field reads, zero cache hits and no `.await` calls (no invalidation value).
- **ResolveResult / ModuleResolveResult helpers** (`primary_modules`, `first_module`, `first_source`, `primary_sources`, `is_unresolvable`, `primary_output_assets`): simple iterators over already-resolved data; converted to plain methods. Added a `Duplicate(usize)` variant to `ModuleResolveResultItem` to handle dedup at construction time instead of in a separate task.
- The basic idea here is that it is reasonable to consume `ResolveResult/ModuleResolveResult` monolithically, and we get little to no benefit from fine grained access. e.g. `is_unresolved()` in theory that is a valuable turbotask, but since it rarely changes but generally if we change how we resolve an import then we have to regenerate code, so saving a few boolean conditions is unlikely to be very valuable.
- Misc: `EcmascriptModuleAsset::analyze`, `is_types_resolving_enabled`, `next_server::resolve::condition`.
### Impact (vercel-site build, dev first-compile)
| Metric | Before | After | Δ |
|---|---:|---:|---:|
| Total cache hits | 30,885,827 | 29,201,314 | −1,684,513 |
| Total cache misses | 6,473,123 | 5,953,626 | **−519,497** |
| Overall hit rate | 82.67% | 83.06% | +0.39 pp |
| Registered task functions | 1,294 | 1,272 | −22 |
The 22 removed tasks were collectively responsible for ~519K misses per build — each miss previously paying the full execution overhead. Most of the work from `EcmascriptModuleAsset::analyze` naturally migrated into `analyze_ecmascript_module` (the task it was wrapping; +129K hits there).
### On-disk cache size (persistent caching)
Each removed task also stops allocating cache cells on disk. Measured on the same vercel-site build with `.next/cache/turbopack` (persistent cache enabled):
| | Size |
|---|---:|
| canary | 2.56 GiB |
| this branch | 2.46 GiB |
| **saved** | **~100 MiB (−3.81%)** |
### Build-time wall clock and peak memory
Ran `pnpm next build --experimental-build-mode=compile` 5 times on each branch
**Peak RSS — clear reduction:**
| | canary | branch | Δ |
|---|---:|---:|---:|
| min | 19.18 GiB | 18.94 GiB | |
| **median** | **19.22 GiB** | **19.01 GiB** | **−217 MiB (−1.10%)** |
| mean | 19.21 GiB | 19.02 GiB | −199 MiB (−1.01%) |
| max | 19.23 GiB | 19.13 GiB | |
Every branch run has lower RSS than every canary run — the distributions don't overlap. Welch's t = −6.03.
**Wall time — no measurable change:**
| | canary | branch | Δ |
|---|---:|---:|---:|
| min | 62.03s | 60.78s | |
| **median** | **62.61s** | **62.65s** | **+0.04s (+0.06%)** |
| mean | 62.83s | 63.80s | +0.96s (+1.53%) |
| max | 64.25s | 68.23s | |
| stddev | 0.84s | 3.42s | |
Median is flat. The mean difference is within noise (Welch's t = +0.61, n = 5). Branch run-to-run variance is higher — one 68.23s outlier pulls the mean up — so this is neither a regression nor a measurable speedup at this sample size.
<!-- NEXT_JS_LLM_PR -->
`NEXT_INSTANT_PREFETCH_HEADER` was replaced by `NEXT_INSTANT_TEST_COOKIE` in #89871. Deleting the dead code. <!-- NEXT_JS_LLM_PR -->
…ns over reporting a failed attempt to validate when a slot is missing (#93714) When instant UI validation cannot successfully complete at a given simluated navigation level it previously would halt the validation there and report the error. This is fine however it is possible that the cause of the impcomplete validation is mundane (i.e. conditionally rendering a slot) and focussing on this lack of ability fully validate a level when other simulated navigations might also provide insights means we might send you down the wrong line of investigation when something more actionable already exists. In the long run these insights ought to be provided through a non-error UI. in that world we'd probably want to perform all the validations to their extent and then simply notify you about which ones could and could not be completed. However since we currently use the error overlay to convey these issues we will favor instead showing actionable errors from any validation depth before showing you less actionable "could not validate" errors
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 : )