`is-error` is a helper that being used accorss client and server now, in
#84909 we switched the underlying safe stringify error implementation to
the precompiled dependency `safe-stable-stringify`. But it increased the
client bundle size a bit.
The change in #84909 was only for applying the `safe-stable-stringify`
for client file logger with mcp, not really necessary need to change for
is-error helper
Note: Save minified around 12kb. it's actually 7.5kb on bundlephobia,
but because we're using ncc to compile it to cjs dependency that the
size seems slightly larger than their metrics. The saved gzip size would
be around 2-3.x kb
This PR fixes a slight performance regression introduced in #85519 where
inline async function expressions were created for each unique set of
arguments passed to a `'use cache'` function.
For a function like this:
```js
export async function getCachedData(id) {
'use cache';
return fetch(`/api/data/${id}`);
}
```
we were previously generating (simplified):
```js
export var $$RSC_SERVER_CACHE_0 = cache("default", "0815", 0, async function(id) {
return fetch(`/api/data/${id}`);
});
```
In #85519, we restructured this to ensure proper stack frames in error
messages (simplified):
```js
export var $$RSC_SERVER_CACHE_0 = React.cache(function getCachedData() {
return cache("default", "0815", 0, async function(id) {
return fetch(`/api/data/${id}`);
}, arguments);
});
```
However, this introduced a small performance issue: the inner async
function expression was passed inline to the cache wrapper. While
`React.cache` memoizes the outer function, each unique set of arguments
would cause a new inner function object to be allocated.
Now we're generating (simplified):
```js
const $$RSC_SERVER_CACHE_0_INNER = async function getCachedData(id) {
return fetch(`/api/data/${id}`);
};
export var $$RSC_SERVER_CACHE_0 = React.cache(function getCachedData() {
return cache("default", "0815", 0, $$RSC_SERVER_CACHE_0_INNER, arguments);
});
```
The cache implementation is now hoisted to module scope with an `_INNER`
suffix as a const declaration with a named function expression. The
function name is preserved to ensure proper stack traces in dev. This
eliminates the repeated function allocations while preserving the
improvements from #85519.
1. Fixed the incremental update bug in buildChunkGraph.
2. Fixed a bug in Rspack's built-in CssChunkingPlugin.
For detailed release information, please see
https://github.com/web-infra-dev/rspack/releases.
Note: All the faulty Rspack test cases on GitHub, from what I can see,
either time out or also produce errors in Rspack version 1.5.0.
---------
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
`createSandbox` fully isolates the returned session from the existing
Next instance by restarting the server.
This is wasteful if the existing instance is already started. Some tests
called `nextTestSetup()` without `skipStart` which got fixed in this PR.
Some tests can just use `patchFile` nowadays instead of `createSandbox`.
Previously we were only showing this during navigations when caches are
bypassed. We want to make it clearer that you are in this state and dev
might not work as intended while caches are disabled.
This will show the cache bypass status on initial load and will reset
the next time a router action occurs that doesn't bypass cache.
https://github.com/user-attachments/assets/f82a98c6-b5be-44d0-ba86-e4f7ca7010e4
In practical terms, clicking the name of a route segment in the Suspense
DevTools should select the child slots of that layout, because when you
focus on it, what you're interested in debugging are navigations that
occur within the shared layout.
So the name we apply to the Activity boundary is actually based on the
name of the *parent* segment.
If a layout or page is marked with "use client", we do not need to pass
any runtime params from the server; the client can parse them from the
URL, or (in the case of a rewrite) from the x-next-rewritten-path and
x-next-rewritten-query headers. This means the client can treat the
segment as fully static, and no dynamic request is necessary upon
navigation.
When `routerBfCache` is enabled, React's Activity API renders inactive
route segments offscreen to enable instant back/forward navigation.
However, the layout-router's lazy data fetching logic was incorrectly
triggering fetchServerResponse calls for these offscreen segments when
data was missing.
This PR adds an isActive prop to InnerLayoutRouter that tracks whether a
segment is currently visible via the existing `stateKey` check.
This removes the Next logo animation/dimming and replaces it with more
explicit states. We also use this UI to show when caches are being
warmed (when using Cache Components). When caches are being bypassed in
DevTools, we also will show this in the indicator with warning text,
indicating that we cannot accurately reflect what can be statically
prerendered.
https://github.com/user-attachments/assets/665d4f8b-8c01-4def-a60e-bc4ecdd1f879
Tweaks the environment label logic to only use label things as
`Prefetch` if there's a runtime prefetch config. If there's none, we
label it as `Prefetchable` instead.
---------
Co-authored-by: Josh Story <story@hey.com>
Various navigation hooks (eg `usePathname`, `useParams`) could suspend
during SSR/prerendering even though they don't necessarily suspend
during client side navigation (because it was likely part of a prefetch
response). React's Suspense DevTools show all the possible things that
could have suspended on the page, but without us calling `use` in these
hooks, there'd be no way for React to track them as IO in the same way
that we do during prerendering.
In development, this instruments all of the client navigation hooks to
call `use` on a fulfilled promise set to the same value that we would
have returned previously. For hooks like `useSelectedLayoutSegment`, I'm
storing a map of promises at each level of layout (because these hooks
take a parallel route key argument and values are relative to the
calling layout's position in the tree). These are eagerly pre-computed
during dev.
Similar to how in DevTools we show if Turbopack is enabled, this shows
that Cache Components is enabled. In the future, we might have a similar
CTA to suggest enabling the feature. For now it only shows if it's
actually enabled.
This moves `experimental.cacheComponents` to a top level config. As part
of this, I disabled some tests in `build-output-prerender` that assert
on `cacheComponents` appearing in the experimental list. In a separate
PR, I'm going to show that Cache Components is enabled next to the
bundler info.
This also updates some docs pages to remove "experimental" language.
This PR extends dev rendering with an extra stage - Runtime, where we
resolve Runtime APIs (`cookies()`, `params`, etc), but not dynamic APIs
(e.g. `connection()`, uncached fetches). This separation requires some
changes to `makeDevtoolsIOPromise` and other tasky delay code that we've
had in place before.|
I've implemented this as `StagedRenderingController` (generally accessed
via `requestStore.stagedRendering`), which allows creating promises that
resolve in the correct stage.
```ts
stagedRendering.delayUntilStage(RenderStage.Runtime, cookiesObject) // resolves in the runtime stage
stagedRendering.delayUntilStage(RenderStage.Dynamic, somethingDynamic) // resolves in the dynamic stage
```
Notably, in the case where the initial render has cache misses and we
only use it as a cache warmup, we can also use this to _not_ resolve
dynamic promises, which saves us from doing some unncecessary (uncached)
work. This means that, if the render ends up being a warmup, dynamic
promises can be left hanging (and later aborted), similar to how
`makeHangingPromise` works in a prerender.
For simplicity and compatibility with other codepaths, most callsites
that need a staged promise still use `makeDevtoolsIOAwarePromise`, but
now they pass in a stage argument to control the timing if we are
rendering with stages.
---
Based on the stage, we now add a third environment label -- "Prefetch",
to correspond with runtime prefetches. This label is currently applied
even if there's no prefetch config in place, which is a bit confusing,
and will be addressed in a follow-up (if there's no runtime prefetch
config, we want to label runtime logs as "Server" even if they run in a
separate stage).
This PR changes the timing used in `CacheSignal.cacheReady()` to work
correctly when rendering, not just prerendering. When rendering, React
schedules new work in `setImmediate` (as opposed to using a microtask
when prerendering), and `CacheSignal.cacheReady()` needs to account for
that, because we need to wait longer to make sure that react had time to
render and thus we've started all the relevant cache reads.
Note that this PR increases the delay for both prerender _and_ render.
This is to make it easier to reason about (by not having separate
codepaths), but also to not be so tightly coupled to React pinging work
in a microtask when prerendering, in case that changes in the future.
This PR replaces the previous approach to the dev-time cache warmup. On
full-page requests, we
1. We attempt an initial RSC render. It uses a RequestStore, but
includes a `cacheSignal` and a `prerenderResumeDataCache` to be filled
1. if there's no cache misses, we use the RSC render as is, and move
onto SSR
2. If there's any cache misses in the static stage (i.e. during the
first timeout), we treat the inital render as a prospective render, use
it only for filling caches, and discard the result
3. Once caches are filled, we render RSC again (using a fresh
RequestStore, with a filled `renderResumeDataCache`), and use this
second stream for SSR instead.
With this strategy, we minimize the amount of work we need to do for
cache warming -- once caches for a page are filled, we can render it in
one go, with no separate cache-filling render necessary.
---
A lot of the effort here goes into trying to reflect the behavior of a
static prerender into what we do during a dynamic render -- if something
would be a dynamic hole (hanging promise) in a prerender, we shouldn't
resolve it microtaskily (in the static stage). Instead, we have to delay
it into a future timeout (the dynamic stage). In this PR, we're still
using `makeDevtoolsIOAwarePromise` for this (i.e. just `new
Promise((resolve) => setTimeout(resolve))`), though this will change to
a more precise mechanism in #84644.
The timing of when promises resolve is currently tested in
`cache-components.dev-warmup.test.ts`, where we check the environment
labels on the server logs replayed in the browser, and use that to
verify which "phase" (Static/Dynamic) a given API resolves in.
This will be the foundation for prefetch validation, where we'll need to
snapshot what was rendered in each stage (Static/Runtime/Dynamic) and
use that to validate whether a prefetch would result in an instant
navigation.
Note that there's currently a bug involving `params` and `searchParams`
-- they can currently incorrectly resolve in the static phase (because
those promises are created before we start the actual render). We're not
(yet) relying on the timing of these promises for anything critical, so
it's fine to leave it for now. This bug will be addressed in #84644,
where I introduce a more precise mechanism for controlling the timing of
promise resolution, which also lets us separate "runtime" APIs like
`cookies` into a separate phase.
---
I've also left the current `spawnDynamicValidationInDev` codepath as is,
so after the we're done with all the render restarting, we'll still kick
off a validation prerender. This will also change in the future (and
could be optimized -- we've already ensured that all the caches are
filled, so we could e.g. skip the prospective render there) but I'm
trying not to do everything at once.
---------
Co-authored-by: Josh Story <story@hey.com>
The peerDeps are already bumped to 19.2.0 at
https://github.com/vercel/next.js/pull/84463, but the test/CNA templates
weren't updated as the `syncPagesRouterReact` value is always false at
the moment, which blocked the update.
Therefore, remove the `syncPagesRouterReact` condition to match the
actual peerDeps bump.
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>
### What?
Adds build-time validation to require explicit `default.js` files for
all parallel route slots (except the implicit "children" slot). This
validation is implemented in both Webpack and Turbopack bundlers.
### Why?
Parallel routes without `default.js` files currently cause silent 404
errors when users navigate to those routes. This creates confusion and
hard-to-debug issues because the routes appear to be configured
correctly but fail at runtime without any indication of what went wrong.
By making this validation explicit at build time, developers get
immediate feedback about missing required files with clear error
messages and documentation links, catching configuration mistakes before
deployment.
### How?
**Rust/Turbopack** (`crates/next-core/src/app_structure.rs`): Added
`MissingDefaultParallelRouteIssue` that emits a build error when a
parallel route slot is missing its `default.js` file. The validation is
skipped for the "children" slot since it's implicit and doesn't require
a default file.
**Webpack**
(`packages/next/src/build/webpack/loaders/next-app-loader/index.ts`):
Added validation that throws `MissingDefaultParallelRouteError` when
`default.js` cannot be resolved. The "children" slot falls back to the
existing `PARALLEL_ROUTE_DEFAULT_PATH` behavior for backward
compatibility.
**Error Class**
(`packages/next/src/shared/lib/errors/missing-default-parallel-route-error.ts`):
New error type with helpful messaging that includes the slot path,
explanation of the requirement, and a link to documentation.
**Migration Path**: Users who want the previous 404 behavior can
explicitly create a `default.js` that calls `notFound()`, or return
`null` for empty slots:
```tsx
import { notFound } from 'next/navigation'
export default function Default() {
notFound()
}
```
Users can also run the following Deno script to generate the default
files for them:
https://gist.github.com/wyattjoh/ba7263ecb637ef399d3e3e4db63ffbd6
**Breaking Change**: This is a breaking change timed for Next.js 16
beta. Builds will now fail if parallel route slots are missing required
`default.js` files.
This hard deprecates the `experimental.ppr` configuration, requiring
users to opt-in instead via `experimental.cacheComponents`. This does
mean that the previous `experimental.ppr = "incremental"` will no longer
be supported.
NAR-433
### What?
This PR removes the automatic ESLint linting that previously ran during `next build`. The documentation has been updated to reflect this change.
### Why?
As part of Next.js 16, we're removing the automatic build-time linting that was previously included in the build process. This gives developers more control over when linting runs by explicitly invoking their linter via npm scripts.
### How?
- Updated documentation to clarify that automatic build-time linting has been removed in Next.js 16
- Removed the `runLint` parameter and related linting code from the build process
- Removed the `verifyAndLint.ts` file which is no longer needed
- Simplified type checking code by removing lint-related functionality
- Removed ESLint telemetry during builds