### Improve performance of chunk bootstrapping leveraging arrays and maps
Currently we bootstrap the set of the modules in a chunk by passing an object to the runtime, this is suboptimal for a few reasons:
* The runtime just wants to iterate the object and copy it into a runtime datastructure and iterating objects is relatively slow
* The browser needs to spend time computing the 'shape' of this object and possibly changing internal representations
The solution to both these problems is of course, Arrays!. so instead of an object like
```
{ [moduleId]: (__turbopack_context__) => {},...}
```
we use an array like this
```
[ moduleId, (__turbopack_context__) => {}]
```
* a non-empty sequence of module ids come first
- we may have more than one to support scope hoisted modules
* the factory function
Because these objects are temporary this should make both constructing and iterating them faster.
Finally, in the runtime what we want to do is copy these modules into a global map that is represented as an `Object`. Because we are constantly inserting new keys, this is a suboptimal case and a `Map` should be faster for both insertions and lookups. So this adapts the moduleFactory type to use an es6 `Map` which is more optimized for this particular usecase.
Ideally we would do the same for the moduleCache but that would complicate `require.cache` usecases. We could perhaps leverage a `Proxy` to maintain support but this is left as future work.
### Aside: why are arrays faster than objects?
Arrays are faster to parse because they incur fewer 'shape transitions' (background reading: https://v8.dev/blog/fast-properties vs https://v8.dev/blog/elements-kinds). Basically for every new property v8 parses on the object literal it changes the hidden type (or 'shape'). For arrays the same thing happens but the process is much simpler as there is a fixed set of possible shapes and the browser will hit the terminal one after evaluating the second element.
Also arrays are simply faster to iterate than objects (but this is generally a non-controversial statement).
### Performance
Based on the `module-cost` benchmark this is a consistent win in all scenarios
| Scenario | Metric | HEAD (ms) | CHANGE (ms) | Delta (ms) | % Change |
|----------|--------|-----------|-------------|------------|----------|
| **Pages API ESM** | Load Duration | 33.46 | 27.87 | -5.59 | -16.7% ✅ |
| | Execution Duration | 63.22 | 62.54 | -0.68 | -1.1% ✅ |
| **Pages API CommonJS** | Load Duration | 44.11 | 33.76 | -10.35 | -23.5% ✅ |
| | Execution Duration | 32.05 | 25.70 | -6.35 | -19.8% ✅ |
| **Client ESM** | Load Duration | 34.74 | 27.65 | -7.09 | -20.4% ✅ |
| | Execution Duration | 46.13 | 40.35 | -5.78 | -12.5% ✅ |
| **Client CommonJS** | Load Duration | 30.43 | 24.48 | -5.95 | -19.6% ✅ |
| | Execution Duration | 25.15 | 17.18 | -7.97 | -31.7% ✅ |
### Risks
The biggest risk of this change is subtle bugs introduced due to `string` vs `number` confusion. I found one subtle issue in how we rewrite `new Worker()` constructors, there could be more not covered by tests.
### What?
In development give the module factory a useful name, so it's clear in stack traces that this is the module evaluation part of the execution.
This also fixes some bugs with the stack trace parser, which seems to struggle if function names contain brackets. The automatically inferred function name would be the module id, which contains brackets.
When validating a dynamic route in dev with Cache Components we must not
use more params than would be know at build time because we want to
ensure dev acts as an appropriate debug environment for build validation
issues. Any time a validation fails for reasons other than fallback
params it would have failed as well with fallback params. So we find the
smallest set of fallback params that would be used during the build
(which might be empty if you provide a complete set through
generateStaticParams) and we use that.
We just need to give a special name to that module so that we can ignore-list it later.
For Webpack I chose the same approach as https://github.com/vercel/next.js/pull/81229. Turbopack already sourcemapped the generated module.
Closes https://linear.app/vercel/issue/NAR-234
RSPack team is informed. Their compat layer doesn't implement `createFilename`
## What?
Rename `experimental.dynamicIO` to `experimental.cacheComponents` across
the Next.js codebase.
## Why?
We're going to be merging the functionality of the `ppr`, `dynamicIO`
and `useCache` experimental flags into the singular `cacheComponents`
flag to reduce complexity of the codebase and simplify adoption for
users wanting to experiment with experimental features.
## How?
- Renamed the configuration option from `experimental.dynamicIO` to
`experimental.cacheComponents`
- Added deprecation handling with automatic migration for the old option
name
- Updated all documentation, tests, and internal references
- Updated Rust code in SWC transforms and Turbopack
- Maintained backward compatibility with deprecation warnings
NAR-158
Format line format: `<segment> [<files,>]`
This will help visualize the rendered segment explorer panel easier by checking the snapshot. e.g.
```
app/ [layout.tsx]
parallel-routes/ [layout.tsx, page.tsx]
@bar/ [layout.tsx, page.tsx]
@foo/ [layout.tsx, page.tsx]
```
Capture defined boundaries (not-found / error / loading) and used to filter which one is available for boundary triggers
The trie will now hold all the defined boundaries, but what's different from the existing rendered boundaries is:
Here's the difference of new defined boundary trie nodes:
```
{
type: "boundary:<type>"
pagePath: "<pagePath>@boundary"
}
```
We add a `boundary:` prefix to determine if it's node representing existence;
We add a `@boundary` suffix to the filename cause the <pagePath> part is still need to use for indexing in the trie, but the `@boundary` doesn't matter yet. We'll remove it once we start using the file name in the dropdown panel
Closes NEXT-4330
### Example
When there's only one not-found.tsx, allow to trigger the not-found boundary and disable the rest.
https://github.com/user-attachments/assets/eb5c49a7-4fd2-496b-b778-fb66581908b3
With recent improvements in React, and after switching to the React
builds for Node.js in #81048, we can now generate better dynamic
validation error stacks in dev mode by utilizing owner stacks instead of
component stacks.
For async I/O, we're using the owner stack exclusively. For sync I/O
we're appending the owner stack to the call stack. In a future iteration
we might instead log the original error as-is where it occurs, and let
`patchErrorInspectNodeJS` handle the owner stack appending as a general
solution.
Additionally, we're now guiding users in the build-time error messages
to using `next dev` for further debugging of dynamic validation errors –
or, alternatively, using `next build --debug-prerender`.
closes NAR-149
Closes https://linear.app/vercel/issue/NEXT-4560/
React now exposes Web stream APIs in their Node.js builds so we can use the Node.js builds.
That enable us to use some of the Node.js goodies like `async_hooks` which is required for the React's experimental Server Requests track.
## Test plan
`next-server` runtimes did not increase bundle size. We even saved some in the `app-page` entries since we no longer have to bundle Edge and Node.js versions of React Server. We can rely solely on the Node.js variant of React Server.
A build of `test/e2e/app-dir/hello-world` shows no significant bundle size changes
These frames will be ignore-listed soon. Until then, we remove them from the test snapshots, because their occurrence seems to be non-deterministic. They come from React's RSC parsing.
Track built-in conventions in segment explorer. The default `global-not-found.js` and `global-error.js` will be displayed.
Their style will be different to the others, we'll follow up in the later PRs.
Closes NEXT-4576
Group all the built-in conventions into `src/client/components/builtin` with the actual same name of the conventions they represent.
e.g.
The default `not-found.js` is `next/dist/client/compoents/builtin/not-found.js`;
The default `global-error.js` is `next/dist/client/compoents/builtin/global-error.js`;
This give us an easier way to track all the builtin conventions. This is also the preparation work for #80961 where we display the builtin conventions in the segment explorer.
We never actually invoked the listeners attached by React. Updates only worked on soft-navigation because we also re-render the DevOverlayRoot and don't bail out anywhere at the moment.
Just invoking the listeners is not sufficient after https://github.com/vercel/next.js/pull/79699 since userspace and dev-overlay would read different versions of `listeners`. I ported the segment explorer into the new folder structure. Updates now flow through the `dispatcher` and then invoking the listeners actually works. Though mid term we should move the segment tree into actual React tree to get rid of the sync updates.
I also noticed that we're missing an implementation for a remove operation which is required to show the correct state during soft navigations.