This PR adds support for showing the original server sources of server
components and server actions in the browser's developer tools.
To accomplish that, we're building on top of #69190, #70563, and #70564,
in which we prepared the proper generation of the source maps.
This PR completes the feature, by wiring up `findSourceMapURL` (see
https://github.com/facebook/react/pull/30741) with a new dev server
middleware that serves those source map files to the browser.
Another change we had to make is disabling the dead-code elimination of
server actions in client bundles (see #70103), but only in development
mode. This optimization is primarily intended for production bundles, so
the change should not pose a problem.
With that, it's now possible to jump directly into the server sources
from the browser's dev tools, e.g. for component stacks of server logs
that are replayed in the browser, or when inspecting server action props
in the React DevTools.
Closes PACK-3270
- Retains sourcemaps for the generated `__turbopack_import__`
statements. At least in dev
- Refactoring to allow simply returning statements to hoist
<br>
- [x] ~~Prevent duplicate `__turbopack_import__` calls when importing
the same module multiple times~~
- [x] ~~The order is slightly different now~~
The warnings are fixed by callsite not by something changing an
abstraction on top of it. That's at least what the codemod assumes.
Basically each warning is now mapped to a change the codemod should've
made but didn't to avoid false-positives (e.g. propagating `async`
across module boundaries).
For browser specific access we don't dedupe since we have no
`React.cache`
fixes a race condition in the `after()`-related test in
`server-components-hmr-cache.test.ts`
i made `getLoggedAfterValue` stricter while investigating an unrelated
issue, and saw it occasionally throw (see [CI
run](https://github.com/vercel/next.js/actions/runs/11001754094/job/30547234764?pr=70362#step:29:708)).
before this change, if `getLoggedAfterValue` was called before any logs
with `"After: "` were written, it would just return `undefined`, which
is obviously not what the test wants. this seems to have been happening
occasionally, but it wasn't visible because even if we got `undefined`
from one of the calls, the
`expect(valueBeforePatch).not.toEqual(valueAfterPatch)` assertion would
still pass -- one of the values is a string and the other is
`undefined`, so obviously they're not equal!
Pages router (`/pages`) will continue to support React 18 not the React
19 RC. Current thinking is that we'll add support for React 19 in Pages
Router once 19 is stable.
This does not affect App Router (`/app`) which continues to use the
latest React Canary (i.e. React 19).
https://github.com/vercel/next.js/pull/65058 is required reading to
understand the changes in this PR
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
`unstable_after` needs to be tested in both nodejs and edge runtimes.
Previously, we set the runtime via `next.patch()`, but this proved
error-prone (e.g. because `sandbox()` call would override this patch,
and not actually run anything in edge...)
This PR makes this more static by splitting the test pages for
`unstable_after` into `/nodejs` and `/edge`, each with a corresponding
`export const runtime = "..."` in its root layout. The pages in `/edge`
mirror the structure of `/nodejs` and reexport components from it (which
makes the tests easier to update than simply duplicating everything).
note that "use client" directives and route segment configs cannot be
reexported and need to be duplicated.
### Why?
In https://github.com/vercel/next.js/pull/68622 we fixed a bug that HMR
breaks when `assetPrefix` is set to full URL.
The fix was targeted to the edge case where the user may set `localhost`
to the `assetPrefix`, and technically, when the request is valid the HMR
should work.
However, we do not recommend this pattern as the `assetPrefix` is
intended to be used for setting a CDN URL.
### How?
Therefore we modify the docs to gently imply that the `assetPrefix` is
for CDN URL.
Also, removed the warning log that could be confusing whether we support
it or not.
Setting localhost will still work, but we do not mention about it within
the app.
### What?
Disables logging when an error is thrown anyway (which will be logged
upstream).
Reduces the errors logged when there is a compiler error to 1, currently
it shows 3 times.
Closes PACK-3170
This moves the static indicator we added for the app router into the dev
overlay so it can share the logic/be aware when either are showing to
coordinate position. This also applies similar design to make the look
more consistent as well.
https://github.com/user-attachments/assets/bca899d4-0635-4868-8284-02f0cb4b5444
Closes: NDX-74
## Description
I discovered a bug related to the coexistence of the app router and
pages router in our application. When a page is being served by the
pages router, any changes to server components (in this case,
`globals.css` imported from `app/layout.tsx`) cause the entire page to
reload, significantly lowering productivity.
I believe this is not the intended behavior since server component
changes should have no impact on pages served by the pages router.
## Investigation
I traced the changes and found that:
- At the point of this PR
(https://github.com/vercel/next.js/pull/41464), the process seems to be
handling this correctly.
- Later, in this PR (https://github.com/vercel/next.js/pull/45268), it
started causing reloads, seemingly intended for the app router but
inadvertently affecting the pages router as well.
Given that separate `hot-reloader-client.ts` files are now being used
for the app router and pages router, it is now possible to correctly
branch the hot-reloading process.
I have tested this change locally and it is working fine.
### Why?
Logging compiled route `GET / in ...` is a very handy feature.
It would be more great if we have an option to opt-out the logging.
### How?
Set `logging` to false in next config.
```js
const nextConfig = {
logging: false,
}
// ...
```
x-ref: #65992
Closes NEXT-3583
Closes NDX-26
---------
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
### What
Align the typeEnv value type with default process env value type `string
| undefined`
### Why?
When the `experimental.typedEnv` is enabled, we generate a `env.d.ts`
file during the Dev Server.
The type for the loaded env values will be `string` on Dev (type
inference).
Since we do not generate the `env.d.ts` file during the build time,
there could be confusion from the difference of env types between the
Dev and Build.
The reason we don't want to strongly type as `string` or `readonly
string` is because the multiple environment: Dev, Preview, Production,
where the env could be different.
If we type in one place based on the loaded .env file, the environment
(like deployment preview or deployment production) might not have these
values in env files or they only have the env vars in Node.js
`process.env`.
So the type file in build could be unpredictable, after discussion we
decided to keep the original type for values, but the keys of envs are
still be able to hint during development.
### How?
Temporarily infer the type as `string | undefined`.
The `typedEnv` will serve as the intellisense (type hint).
Closes NDX-84
This adds support for caching `fetch` responses in server components
across HMR refresh requests. The two main benefits are faster responses
for those requests, and reduced costs for billed API calls during local
development.
**Implementation notes:**
- The feature is guarded by the new experimental flag
`serverComponentsHmrCache`.
- The server components HMR cache is intentionally independent from the
incremental cache.
- Fetched responses are written to the cache after every original fetch
call, regardless of the cache settings (specifically including
`no-store`).
- Cached responses are read from the cache only for HMR refresh
requests, potentially also short-cutting the incremental cache.
- The HMR refresh requests are marked by the client with the newly
introduced `Next-HMR-Refresh` header.
- I shied away from further extending `renderOpts`. The alternative of
adding another parameter to `renderToHTMLOrFlight` might not necessarily
be better though.
- This includes a refactoring to steer away from the "fast refresh"
wording, since this is a separate (but related) [React
feature](https://github.com/facebook/react/issues/16604#issuecomment-528663101)
(also build on top of HMR).
x-ref: #48481
## Background
Currently in app router during development all pages are dynamic
rendered and streamed since we don't know if a page will be prerendered
until after the page is rendered. During build time we do a render pass
for each path and if it doesn't bail from static generation it is
considered prerendered/ISR'd.
Since it can be tricky to track all the bail outs for static generation
and doing numerous builds to track this isn't feasible we want to have
some sort of signal in development to show if it would have been
prerendered.
## New Handling
To alleviate the above pain point we are planning to bring back the
prerendered indicator from pages initially and have a config to disable
if desired. We are also going to investigate other possible indicators
potentially through headers or similar.
<details>
<summary>Preview</summary>


</details>
---------
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
...with `assertHasRedbox` and `assertNoRedbox`.
`hasRedbox()` has a hardcoded timeout of 5s that is only required for
the negative assertion.
Instead, we now have dedicated assertions for the positive
(`assertHasRedbox`) and negative case (`assertNoRedbox`).
The negative assertion still has the hardcoded timeout.
But the positive assertion just retries until we find the Redbox.
This speeds up tests using the positive assertion.
Removing `hasRedbox` also uncovered some unused expressions e.g. `await
hasRedbox(browser)`.
These expressions probably wanted to use `expect(await
hasRedbox(browser)).toBe(true)
## Why?
For multi-root layouts (route groups on the root with their root
layouts, no layout file on the root), it is not possible to use global
`not-found` since the `layout` is missing on the root.
```sh
.
└── app/
├── (main)/
│ └── layout.js
├── (sub)/
│ └── layout.js
└── not-found.js --> ERR: missing layout
```
Current Behavior:
```sh
not-found.js doesn't have a root layout. To fix this error, make sure every page has a root layout.
```
## What?
Let multi-root layouts also benefit from the global `not-found`.
## How?
Wrap root `not-found` with default layout if root layout does not exist.
Although this solution is not `multi-root` specific, it won't produce
critical issues since a root `layout` is required for other cases.
Fixes#55191#54980#59180