* Add docs link to the warning, add codemod link to viewport docs section
* Only log the warning once after the metadata resolving process, this will avoid multiple duplicated logs showing for one page.
Closes NEXT-1723
### What?
Rewrites to an edge route currently throw an invariant rather than properly serving up the page that is rewritten to.
### Why?
The `NextRequest` object that is provided to the edge route handler contains pathname information only for the "origin" request (e.g., when visiting `/one/example` which rewrites to `/two/example`, the pathname is still `/one/example`. This hits an invariant since the route matcher is unable to find `/one/example` since it does not exist.
### How?
This updates the module wrapper to grab the pathname from the route definition rather than the request object. For dynamic segments, we extract them from `request.nextUrl` since we know that even if `nextUrl` is referencing the origin path, the parameters it has are relevant for the rewrite.
This adds the `getUtils` utility that's also used in base-server to handle the URL normalization, which also provides an interface for normalizing dynamic params from a `ParsedUrlQuery`.
Closes NEXT-1724
Fixes#48295
This PR fixes an issue where users would try to access `req.cookies` from a route handler and be unable to read from it.
This issue was caused by `req.cookies` not opting you into dynamic behaviour, unlike `cookies()` from `next/headers`. This fixes it.
### What?
When a layout segment forces dynamic rendering (such as with
`force-dynamic` or `revalidate: 0`), navigating to sub-pages of that
layout will attempt to re-render the layout, also resulting in side
effects re-running. This means if your layout relies on a data fetch and
you render the result of that data in the layout, it will unexpectedly
change when navigating between sub-paths, as described in #57326.
As a separate issue (but caused by the same underlying mechanism), when
using `searchParams` on a dynamic page, changes to those search params
will be erroneously ignored when navigating, as described in #57075
### Why?
As a performance optimization we generate static prefetch files for
dynamic segments ([original
PR](https://github.com/vercel/next.js/pull/54403)). This makes it so
that when prefetching is turned on, the prefetch can be served quickly
from the edge without needing to invoke unnecessarily. We're able to
eagerly serve things that can be safely prefetched. This is nice for
cases where a path has a `loading.js` that we can eagerly render while
waiting for the dynamic data to be loaded.
This causes a problem with layouts that opt into dynamic rendering: when
the page loads and a prefetch is kicked off for the sub-page, it'll load
the static prefetch, which won't be generated with the same router state
as the dynamically rendered page. This causes a mismatch between the two
trees, and when navigating within the same segment, a refetch will be
added to the router because it thinks that it's navigating to a new
layout.
This also causes issues for dynamic pages that use `searchParams`. The
static prefetch will be generated without any knowledge of search
params, and when the prefetch occurs, we still match to the prefetch
generated without search params. This will make the router think that no
change occurs, and the UI will not update to reflect the change.
### How?
There's ongoing work by @acdlite to refactor the client router.
Hopefully it will be easier to re-land this once that work is finished.
For now, I've reverted the behavior as it doesn't seem to be worth the
bugs it currently causes. I've also added tests so that when we do
re-land this behavior, we can catch these subtleties.
Fixes#57326Fixes#57075
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
### What?
I changed the behavior of fetch() when 'force-dynamic' is specified in the `dynamic` of Route Segment Config to be similar to when 'force-no-store' is specified in `fetchCache`.
### Why?
The document (https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic) contains an explanation that when 'force-dynamic' is specified for `dynamic`, it will behave equivalently to the following:
> Setting the segment config to export const fetchCache = 'force-no-store'
I tried to correct it because it was not actually behaving this way.
### How?
When determining if `fetchCache` is 'force-no-store', I have modified the code to also check the `dynamic` setting.
Fixes#47033
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
### What?
When using a `Request` object with fetch, we'll log a warning indicating that using the `cache` property in addition to `revalidate` is unsupported.
### Why?
`Request` sets some defaults on the request init, such as `cache: "default"`. This makes the warning confusing and there's no way to avoid it aside from switching the resource argument to be a URL string instead.
### How?
This keeps existing behavior but omits the log in the case where a request object is used and no explicit cache overrides are specified.
Fixes#58109
### Issue
In the client components world, when you're using `next/dynamic` with `ssr: false` to split chunks in pages of edge runtime, you could get the dynamic imported module still bundled in the server bundle for edge runtime. This could easily hit the bundle limit on edge runtime if you're loading a large size of non-SSR module.
This is caused by the whole chunk is still being included when we're creating the client entry. Since the client entry is imported eagerily, webpack will bundle all the modules under it, unless it's explicitly marked not being included.
### Fix
For client components, SSR rendering layer of bundle, non-SSR `next/dynamic` calls, we're transform the result of `dynamic()` call from to conditional import the dynamic loaded module.
From
```js
dynamic(() => import(...))
```
To
```js
dynamic(() => {
require.resolveWeak(...)
}, { ssr: false })
```
This will only be applied to SSR layer bundle client components non-SSR `next/dynamic` calls and only when webpack is bundling since turbopack doesn't need this. In this way, the server side will be stripped but it can still enter the module graph since we need to traverse if there's SA in client modules with using webpack API `require.resolveWeak`. And for client side bundle will still include the actual module.
Close NEXT-1703
Co-authored-by: @BRKalow <bryce@clerk.dev>
### What?
A number of our customers have been experiencing issues stemming from an
`x-forwarded-host` header that doesn't match the `host` header.
### Why?
[This PR](https://github.com/vercel/next.js/pull/57815) removes
functionality which sets `x-forwarded-host` to `req.headers['host']` and
relies solely on the server's hostname and port.
This can be seen locally when visiting the app via a localhost
subdomain.
The `x-forwarded-host` header will remain as `localhost:${port}` while
the actual requested host will contain the subdomain.
### Related
- https://github.com/vercel/next.js/pull/57815#issuecomment-1808496790
---------
Co-authored-by: BRKalow <bryce@clerk.dev>
Co-authored-by: Zack Tanner <zacktanner@gmail.com>
### What?
When navigating between pages (via `prefetch: false`) within a dynamic
segment, the shared layout is re-rendered. This can cause unexpected
behavior like layout data changing when navigating between child
segments.
### Why?
When prefetch is false, we're currently opting into an "optimistic
navigation" codepath, which will optimistically render layout-routers up
to the point where data is missing, while kicking off data fetches. It
attempts to determine where refetching needs to happen by traversing the
router cache nodes and checking where data is missing. However, it
locates these cache nodes by using "segments" obtained by
[deconstructing the
URL](https://github.com/vercel/next.js/blob/fix/optimistic-bailout/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts#L142),
which won't accurately contain dynamic segment data. For ex, `/en` which
corresponds with `/app/[lang]/page.tsx` will have a cache node key of
`lang|en|d`, not `en`. Similarly, the optimistic tree that gets
constructed will also be incorrect, since it uses the URL segment.
### How?
My initial fix was to match the dynamic segment against the segment
constructed by the URL. But after discussion with @sebmarkbage and the
team, it seems more correct to remove the optimistic case all together
as there's no guarantee that the url will actually match to that
segment.
Fixes#50670
---------
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
### What?
Using `revalidateTag` or `revalidatePath` in a route handler will not
currently opt the handler into dynamic behavior. This means that if you
use these APIs and don't opt into dynamic behavior by some other means,
the revalidation call won't do anything as the route handler will be
served statically.
### Why?
During static generation, we do not currently indicate that usage of
these APIs should opt into dynamic usage.
### How?
This updates `revalidateTag` to throw a `DynamicUsageError` (similar to
our other scenarios, such as search params bailout, headers/cookies, or
fetch + revalidate/no-store)
Closes NEXT-1712
Requires vercel/turbo#6388
This uses the structure implemented in vercel/turbo#6388 to support formatted text when reporting. Right now only the `Line` and basic `String` cases are handled.
## Description
Between 14.0.2-canary.6 and 14.0.2-canary.7, a change was introduced in vercel/next.js#56497 that turned the Redux store state into a Promise, rather than a synchronous state update.
This caused the `sync` function -- used to send state updates to the Redux Devtools -- to be recreated on every dispatch, which in turn, by referential instability, caused the `HistoryUpdater` component to re-render and trigger a `history.replaceState` with no particular change, but with the internal `canonicalUrl`.
When an app does a soft/shallow navigation by calling history methods directly (currently the only way to do shallow search params updates in the app router), these changes would have been overwritten by any prefetch (eg: hovering or mounting a Link), which is usually a no-op for the navigation state.
This PR changes the `sync` function to take the state as an argument rather than as a closure. The whole app router state is also unwrapped only once, and fed to the HistoryUpdater. Changes to its contents made by reducers will cause the HistoryUpdater effect to re-run, triggering history updates and a call to the sync function.
## Context
I maintain [`next-usequerystate`](https://github.com/47ng/next-usequerystate), which is used in the Vercel dashboard, and which is impacted by this change (see
[#388](https://github.com/47ng/next-usequerystate/issues/388)).
## History
@timneutkens introduced the `sync` function and the whole Redux devtools reducer in vercel/next.js#39866, with the note:
> a new hook useReducerWithReduxDevtools has been added, we'll probably want to put this behind a compile-time flag when the new router is marked stable but until then it's useful to have it enabled by default (only
when you have Redux Devtools installed ofcourse).
If a different direction is needed to keep sending `RENDER_SYNC` actions to Redux devtools, I'll be happy to rework this PR to move the `sync` function into the action queue.
## Changes
- [x] Added e2e test. Requires a `start` mode as prefetch links are disabled in development. Test was verified to fail from next@>=12.0.2-canary.7 without the fix.
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:
## For Contributors
### Improving Documentation
- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide
### Adding or Updating Examples
- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md
### Fixing a bug
- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md
### Adding a feature
- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md
## For Maintainers
- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change
### What?
### Why?
### How?
-->
This PR fixes a bug where the expected catch-all route would not match
if there were multiple "catch-all routes" under the "parallel route”.
The page on the non-parallel routes path matches the catch all routes.
that exist on the more detailed path.
However, under parallel routes, it matches the most parent page of all
the pages with catch all routes.
For example, if there are files like below:
```
app/@sidebar/[...catchall]/page.tsx
app/@sidebar/dashboard/[...catchall]/page.tsx
```
When accessing `/foo`, it should match
`app/@sidebar/[...catchall]/page.tsx`, and this is working correctly.
However, when accessing `/dashboard/foo`, it should match
`app/@sidebar/dashboard/[...catchall]/page.tsx`, but
`app/@sidebar/[...catchall]/page.tsx` is being matched instead.
## Repository to reproduce
https://github.com/nonoakij/fix-parallel-routes-with-catch-all
## Related PR
https://github.com/vercel/next.js/pull/58215
---------
Co-authored-by: Jimmy Lai <laijimmy0@gmail.com>
## What?
This PR introduces support for manually calling `history.pushState` and `history.replaceState`.
It's currently under an experimental flag:
```js
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
experimental: {
windowHistorySupport: true,
},
}
module.exports = nextConfig
```
Going forward I'll refer to `history.pushState` as `replaceState` is interchangable.
When the flag is enabled you're able to call the web platform `history.pushState` in the usual way:
```js
const data = {
foo: 'bar'
}
const url = '/my-new-url?search=tim'
window.history.pushState(data, '', url)
```
Let's start by explaining what would happen without the flag:
When a new history entry is pushed outside of the Next.js router any back navigation to that history entry will cause a browser reload as it can no longer be used by Next.js as the required metadata for the router is missing. In practice this makes it so that pushState/replaceState is not feasible to be used. Any pathname / searchParams added can't be observed by `usePathname` / `useSearchParams` either.
With the flag enabled the pushState/replaceState calls are instrumented and is synced into the Next.js router. This way the Next.js router's internal metadata is preserved, making back navigations apply still, and pathname / searchParams is synced as well, making sure that you can observe it using `usePathname` and `useSearchParams`.
## How?
- Added a new experimental flag `windowHistorySupport`
- Instruments `history.pushState` and `history.replaceState`
- Triggers the same action as popstate (ACTION_RESTORE) to sync the provided url (if provided) into the Next.js router
- Copies the Next.js values kept in history.state so that they are not lost
- Calls the original pushState/replaceState
~~Something to figure out is how we handle additional pushes/replaces in Next.js as that should override the history state that was previously set.~~
Went with this after discussing with @sebmarkbage:
- When you open a page it preserves the custom history state
- This is to solve this case: when you manually `window.history.pushState` / `window.history.replaceState` and then do an mpa navigation (i.e. `<a>` or `window.location.href`) and the navigate backwards the custom history state is preserved
- When you navigate back and forward (popstate) it preserves the custom history state
- When you navigate client-side (i.e. `router.push()` / `<Link>`) the custom history state is not preserved
This PR fixes a bug where parallel routes would not apply appropriately on navigation when used within slots.
The following scenarios:
```
/foo
/bar
/@slot
/[...catchAll]
```
or
```
/foo
/[...catchAll]
/@slot
/bar
```
will now function correctly when accessing /foo/bar, and Next.js will render both /bar and the catchall slots.
The issue was that the tree constructed by `next-app-loader` for a given path, /foo/bar in the example, would not include the paths for the catch-all files at build time. The routing was done 1-1 when compiling files, where a path would only match one file, with parallel routes, a path could hit a defined path but also a catch all route at the same time in a different slot.
The fix consists of adding another normalisation layer that will look for all catch-all in `appPaths` and iterate over the other paths and add the relevant information when needed.
The tricky part was making sure that we only included the relevant paths to the loader: we don't want to overwrite a slot with a catch all if there's already a more specific subpath in that slot, i.e. if there's /foo/@slot/bar/page.js, no need to inject /foo/@slot/bar/[...catchAll].
One thing that is not supported right now is optional catch all routes, will add later.
fixes#48719fixes#49662
Instead of requiring React in `maybePostpone` (which is susceptible to referencing the wrong version of React during build time, such as in the case where the static worker patches fetch within an app-route, which doesn't have an experimental runtime), this provides the postpone API to the `staticGenerationStore`. That way we know the API is available in render which is when we'd expect to postpone.
The "postpone" terminology is internal to React and can be used for more
things than just this. It's also a mechanism we may or may not rely on.
---------
Co-authored-by: Zack Tanner <zacktanner@gmail.com>
This PR fixes the bug in which interception routes of the form `(.)[param]` would not intercept navigations.
The bug happened because we would not create a dynamic route matcher for the intercepted route, so we would never match the correct dynamic route when hitting the server, falling back to the base one.
The fix consists of fixing the logic that checks for a dynamic route so that it checks the correct path when handling an interception route.
There's probably a better fix here, advice welcome
fixes#52533
Fixes two build output logs:
- A page that uses `generateStaticParams` & postpones should be marked as partially prerendered
- Assume pages that contain dynamic segments will postpone when PPR is enabled even though it won't be determined until request time
When `patchFetch` is applied at during `buildAppStaticPaths` ([ref](030021234b/packages/next/src/build/utils.ts (L1253-L1256))), it's done so without any context of the bundled React runtime.
Since `patchFetch` will potentially postpone during static generation with PPR, it needs to be using the correct React version, otherwise `unstable_postpone` won't be available e.g. in the case of a page utilizing `generateStaticParams`.
This moves `patchFetch` into the bundled runtime so that it has the correct version of React when invoked.
We had added encoding the client component assets loaded from RSC manifest that we need to encode them to make sure when they're loaded on server and sent to client, the client will receive the encoded one. But the override of the webpack chunk loading method could be loaded later than react related chunks, that when client component is loaded first (e.g. `next/script`) and it triggers react loaded ealier than the overriding. Then the chunk could be encoded incorrectly.
Discussed with @gnoff and put this out as the 1st step solution to ensure the order. in the future we can try to get rid of the encoding by providing safer url
Fixes#57829
A shared incremental cache IPC server was introduced for build-time static workers as an optimization to dedupe fetch requests, however this can cause fetch-related flakiness to builds under certain conditions (e.g., large payloads).
This moves the optimization behind an experimental flag to unblock those running into IPC-related build time errors while we work on an alternative solution for the underlying issue
Fixes#53695
This removes our current convention of throwing promises in reducers in
favor of returning promises that can be consumed by `use` instead. This
will help unblock some future improvements (batching, PPR)
Reducers that would typically throw a promise now return their promise.
This gets maintained by a mutable queue (initialized in hydrate) to
ensure actions are processed in-order. The queue is also responsible for
mutating state and passing it as an input to subsequent actions.
This PR does not modify reducer behavior to keep changes minimal, but
there's more cleanup that we can do in a follow-up PR to remove things
that previously assumed reducers would be replayed.
(I recommend reviewing with whitespace turned off)
---------
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
When postpone is caught by user code, this will cause PPR not to properly prerender the static parts and thus we need to fail the build. This also adds some messaging about how to fix the error.
Prior to this change, catching code that would normally trigger `postpone ` would silently fail, but the build outputs would be incorrect as there's no postpone data available.
Relands #57477 with additional tests & fixes
Reduce the confusiong of the the logging of pages, make it easier to understand
* Removing the trailing `/page`, `/route` suffix
* Removing the internal segment like `[[...__metadata__]]`
#### After
```
○ Compiling / ...
○ Compiling /dynamic/[slug]/icon ...
```
#### Before
```
○ Compiling /page ...
○ Compiling /(group)/dynamic/[slug]/icon-ahg52g/[[...__metadata_id__]]/route ...
```
Closes NEXT-1701
This new option specifies a list of host names that are considered safe, to accept as Server Action requests if they're different from the initial request origin. It can be very helpful when the hosted app has many layers of reverse proxies ahead.
Closes#57397.
### What?
Follow-up of #56797
While working on this, I noticed that some logic around stripping internal headers was duplicated, so I did some cleanup too.
### Why?
In #56797 we set these headers, but it only affected Route Handlers, Middleware is still missing them, which is a regression introduced in #52492
(Related: https://github.com/vercel/next-learn/issues/252)
### How?
Move to set these headers up to `base-server.ts` so they are present in Middleware too.
> Note: All headers are set with `??=` to respect the original value if set (with other words, only add these headers if they aren't set yet)
Closes NEXT-
Fixes#52266
For app router bundling layers "SSR rendering" and "browser" layer, which are used for server side rendering and client, we should still apply the module resolving rules to all assets since we bundled everything, removed the default exclude conditions as they'll not apply the rules to node_modules. That could cause the mismatch resolving for package.
E.g. You have two dual packages A and B are both compatible for ESM and CJS, and both have default export. B is depent on A, but when you import B in a client component that will be SSR'd, it's picking up the CJS asset like the case described in #57584 .
Fixes#57584
Closes NEXT-1702
### What?
Wraps up metadata-dynamic-routes tests fixes for the turbopack. There is 1 remaining failing test due to lacks of supporting `import.meta.url` which need to be addressed separately.
I spent amount of time why turbopack cannot find the route for the dynamic metadata for a certain route. In the end, found there are mismatching expectations for the route due to different hash for the certain route. We do use the same djb2 hash between next.js and turbopack both, so it was quite confusing why we don't get deterministic hash.
After trying some experiments, found out root cause was how 2 different runtimes handle overflow for given type of numbers. In rust + turbpack we use u32 and do 32-bit hash calculation for given string, while in js we implicitly used number type as is, in result overflow occurs with default 53-bit float.
Originally I tried to adjust hash in turbopack side to preserve js hash as-is, but so far I found it was non trivial to do so as rust there's no out of the box types we can coerce to the js number type. In result, unlike other fixes in turbopack this PR changes how js hash is being generated. I hope this woulndn't be a breaking changes; expect so since this is a metadata specific hash that we do not have written spec for it.
Closes WEB-1890
This removes the ignores for dev react bundles which was added as an
optimization but causes issues when react is imported from an ESM module
since all requires are being analyzed for named exports.
Fixes#57582
Displaying hints of "missing default export" if you didn't properly export the `default` handler for og image
```
▲ Next.js 14.0.1-canary.2
- Local: http://localhost:3000
✓ Ready in 1089ms
✓ Compiled /opengraph-image/[[...__metadata_id__]]/route in 211ms (44 modules)
⨯ Error: Default export is missing in "/Users/huozhi/workspace/next.js/test/e2e/app-dir/metadata-dynam
ic-routes/app/opengraph-image.tsx"
at eval (webpack:///app/opengraph-image.tsx?3407:11:1)
at (app-metadata-route)/../../../../packages/next/dist/build/webpack/loaders/next-metadata-route-lo
ader.js?page=%2Fopengraph-image%2F%5B%5B...__metadata_id__%5D%5D%2Froute&isDynamic=1!./app/opengraph-im
age.tsx?__next_metadata_route__ (/Users/huozhi/workspace/next.js/test/e2e/app-dir/metadata-dynamic-rout
es/.next/server/app/opengraph-image/[[...__metadata_id__]]/route.js:362:1)
at __webpack_require__ (/Users/huozhi/workspace/next.js/test/e2e/app-dir/metadata-dynamic-routes/.n
ext/server/webpack-runtime.js:33:42)
```
Scope all `serverActions` config in one group "serverActions" to make it
more semantics
---------
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Rather than sending a warning, we should fail the build if a postpone
call is caught. We should also fail the build if there are any errors
during static generation similar to the non-ppr case.
---------
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
### What?
Adds support for Server Actions imported by both server and client.
### Why?
If an Action is imported by both the Client and RSC layers, we need to
support them as if they're the same action.
### How?
First, we need to ensure both layers create the same action hash ids,
which we can then use to deduplicate actions imported by both layers. If
a conflict is found, we prefer the RSC layer's action.
Closes WEB-1879
---------
Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>