Currently using server actions on a page or using edge runtime causes
that page to bail out of ISR or static generation so this adds warnings
to make users aware of this.
x-ref: [slack
thread](https://vercel.slack.com/archives/C03KAR5DCKC/p1690816539472449)
---------
Co-authored-by: Zack Tanner <zacktanner@gmail.com>
## What?
I was investigating reports of server actions with `revalidatePath` /
`revalidateTag` not invalidating the client-side router cache. Managed
to reproduce the issue here:
https://github.com/timneutkens/server-actions-test (requires Vercel KV
to run).
While looking at the reducer I noticed a few things that seemed off:
- setTimeout to trigger another `dispatch` on the same reducer with the
fetched data. This means that it would not be part of the same React
Transition.
- redirects weren't applying the data that comes back from the server
(that allows for single hop navigation)
- prefetchCache was invalidated, but the router cache which is used for
back/forward navigation was not invalidated, causing back/forward to not
get the new data.
- all changes in the action-reducer mutate. The part that shouldn't
mutate was part of that setTimeout dispatch.
This PR aims to solve all of these by reworking the actions reducer to
be handled similarly to `router.refresh()`. Since `router.refresh()` was
already modeled to be similar to `revalidatePath('/')`.
The flow is now more like the other reducers:
- Fetch data
- Wait for the data to come back
- Apply the data to the cache and keep it in a mutable variable
- Return the new cache and otherwise values like the url
In particular the actions reducer handles a few extra specifics:
- Resolving the server action promise, so that the value is passed to
the application code waiting for the result.
- Applying redirects from `redirect()` calls.
- Invalidating the router cache
## Followup changes
- Currently when calling `revalidatePath('/dashboard')` the entire
router cache is invalidated instead of only `/dashboard` and further
down, this is not in scope for this PR but still has to be added.
- `notFound()`, I'm not sure how this is supposed to work exactly, it
doesn't really make sense to me to allow it in server actions.
Kudos @feedthejim for helping investigate for this PR 😌
<!-- 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?
Closes NEXT-
Fixes #
-->
This PR reverts a change that removed the `content-length` header filtering from the req made by the actions when redirecting. This change made some tests flaky and presumably also broke server actions in subtle ways.
There's still one other bug when redirecting after revalidating that will happen in you revalidate a page that was already rendered before where we will still show stale content. @timneutkens is fixing that one.
NEXT-1483
This uses an IPC server (if available) for incremental cache methods to help prevent race conditions when reading/writing from cache and also to dedupe requests in cases where multiple cache reads are in flight. This cuts down on data fetching across the different build-time workers.
Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
This PR tries to address some feedback around prefetching, like in #49607, where they were some warnings because we were over prefetching.
The tweaks in this PR:
- if there are no loading boundary below, we don't prefetch the full page anymore. I made that change a while ago but I think it wasn't the original intent from @sebmarkbage. Fixing that now. So now, we will prefetch the page content until the nearest loading boundary, only if there is any.
- there's now a queue for limiting the number of concurrent prefetches. This is to not ruin the bandwidth for complex pages. Thanks @alvarlagerlof for that one.
- also, if the prefetch is in the queue when navigating, it will get bumped.
- bonus: fixes a bug where we were wrongly stripping headers in dev for static pages
Test plan:
<img width="976" alt="CleanShot 2023-07-20 at 17 53 43@2x" src="https://github.com/vercel/next.js/assets/11064311/2ea34419-c002-4aea-94df-57576e3ecb2e">
In the screenshot you can see that:
- only 5 requests at a time are authorised
- when I clicked on 15, it got prioritised in the queue (did not cancel the rest)
- the prefetch only included the content until the loading boundary
Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
### What
This PR changes the flow of not-found rendering process.
### Why
`not-found.js` was rendered in two ways before:
* 1 is SSR rendering the not-found as 404
* 2 is triggering the error on RSC rendering then the error will be
preserved in inline flight data, on the client it will recover the error
and trigger the proper error boundary.
The solution has been through a jounery:
No top-level not found boundary -> introduce metadata API -> then we
create a top level root not found boundary -> then we delete it due to
duplicated rendering of root layout -> now this
So the solution before this PR is still having a root not found boundary
wrapped in the `AppRouter`, it's being used in a lot of places including
HMR. As we discovered it's doing duplicated rendering of root layout,
then we removed it and it started failing with rendering `not-found` but
missing root layout. In this PR we redesign the process.
### How
Now the rendering architecture looks like:
* For normal root not-found and certain level of not-found boundary
they're still covered by `LayoutRouter`
* For other error renderings including not-found
* Fully remove the top level not-found boundary, when it renders with
404 error it goes to render the fallback page
* During rendering the fallback page it will check if it should just
renders a 404 error page or render nothing and let the error from inline
flight data to trigger the error boundary
pseudo code
```
try {
render AppRouter > PageComponent
} catch (err) {
create ErrorComponent by determine err
render AppRouter > ErrorComponent
}
```
In this way if the error is thrown from top-level like the page itself
or even from metadata, we can still catch them and render the proper
error page based on the error type.
The problematic is the HMR: introduces a new development mode meta tag
`<meta name="next-error">` to indicate it's 404 so that we don't do
refresh. This reverts the change brougt in #51637 as it will also has
the duplicated rendering problem for root layout if it's included in the
top level not found boundary.
Also fixes the root layout missing issue:
Fixes#52718Fixes#52739
---------
Co-authored-by: Shu Ding <g@shud.in>
Adds a regression test for testing progressive enhancement of Server
Actions. Both when passed from a Server Component and when imported into
a Client Component.
#51723 landed a bit too early which broke this but it'll be fixed again
once React is upgraded.
Co-authored-by: Shu Ding <g@shud.in>
Currently we are validating the `experimental.serverActions` flag when creating the actual entries for Server Actions, this causes two problems. One is that syntax errors caught at compilation time are still shown, even if you don't have this flag enabled. Another problem is we still traverse the client graph to collect these action modules even if the flag isn't enabled.
This PR moves that check to be happening at compilation time, which addresses the two above but also brings the extra benefit of showing the exact span and module trace that errors:
<img width="974" alt="CleanShot 2023-07-03 at 20 26 34@2x" src="https://github.com/vercel/next.js/assets/3676859/1676b1f6-e205-4963-bce4-5b515a698e9c">
Removed an unnecessary dependency mapping from the plugin.
Here's a quick visualization of this change. We have to traversal the module graph twice. The first iteration goes through all server modules and creates the client entries. And the second iteration collects info from all client modules.
Before this PR, the second iteration starts from server entries so it traversals both layers. With this PR, the second iteration will start from client entries only:
<img width="870" alt="CleanShot 2023-06-27 at 10 01 08@2x" src="https://github.com/vercel/next.js/assets/3676859/f0b7a0c6-0ade-483a-8645-48e2a8a6c9d0">
This is a ~100ms improvement for HMR of complicate apps.
Close the circle after #51104. The name "size limit" can be confusing as it could also mean the size of the Server Action function itself, so this PR changes it to `serverActionsBodySizeLimit` and makes sure it's well documented.
<!-- 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
- 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?
Add configuration options to modify the `bodyParser` size as it used to
be available in Page Router.
### Why?
Server Actions "Error: Body exceeded 1mb limit" cannot be resolved since
the body-parser limit size is hardcoded to `1mb`.
### How?
Closes NEXT-
Fixes #
-->
### What?
Add configuration options to modify the `bodyParser` size as it used to
be available in Page Router for APIs.
```js
export const config = {
api: {
responseLimit: false | '8mb'
},
}
```
Reference: [API Routes Response Size
Limit](https://nextjs.org/docs/messages/api-routes-response-size-limit)
### Why?
Server Actions "Error: Body exceeded 1mb limit" cannot be resolved since
the body-parser limit size is hardcoded to `1mb`.
```js
// /packages/next/src/server/app-render/action-handler.ts
// ...
const actionData = (await parseBody(req, '1mb')) || ''
// ...
```
Reference:
https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/action-handler.ts#L355
### How?
- Added option "serverActionsLimit" as `SizeLimit` type to
`config-shared.ts`
- Modified `action-handler.ts` to validate `serverActions` &
`serverActionsLimit` options in nextConfig
- Added conditional `serverActionsLimit` value and `1mb` if falsy
**Working on testing**
Fixes#49891 | #51097 | #51099
---------
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Shu Ding <g@shud.in>
Currently an "action module" (files with `"use server"` on top) can be
imported by both the server and client layers. In that case, we can't
fork that action module into two modules (one on the server layer, one
on the action layer), but only create it once on the server layer.
This ensures that the action module instance doesn't get forked.
Closes#50801.
fix NEXT-1265
There're 3 layers in the RSC module graph: server → client → action. "Action" means that a Client Component re-enters the server layer by importing a file with `"use server"`, and it should behave the same as the server layer but you can't enter the client layer again (hence we have a 3rd layer name).
Since the action layer has the same behavior and module resolution rules, it should be bundled just like the server layer.
Closes#50658. Originally the issue was that `auth/next` isn't being bundled on the action layer, and it has the async local storage imported. Because of that, that storage comes from node_modules instead of the server bundle.
fix NEXT-1290
Make sure we are using `var` instead of `const` as we always put the new
appended statements to the end of the module body, but they can still be
referenced before in the HOC case in the runtime. This causes a runtime
error.
Tl;dr: `a = 1; var a` is fine, but `a; const a = ...` will result in a
compilation error.
Closes#49344.
Similar to tags and paths, when `cookies().set()` is called we have to
invalidate the client router cache as well so routes with
`cookies().get()` will not holding the stale data. This is critical for
auth and other scenarios.
In the future we can have an optimization to only invalidate routes that
actually rely on cookies, similar to paths.
This makes sure that if `revalidateTag` is called in a Server Action, the client router cache and prefetch cache are invalidated correctly so following navigations won't reuse the cache that might hold stale data.
Similar case for `revalidatePath`. I left a TODO where we can't just invalidate the subtree under the revalidate paths because of current implementation limitations. To ensure correctness, we just do the same as `revalidateTag`.
This breaks up some of our longest running tests which allows more
parallelizing of the tests. This also moves turbopack tests filtering
back to an allow list as it is running a lot of unrelated tests
currently which isn't ideal. We should only be running against tests
that are explicitly testing turbopack e.g. build tests should not be
duplicated in the turbopack group.
```sh
test/integration/css/test/group-1.test.js: 762.655
test/integration/edge-runtime-module-errors/test/index.test.js: 695.309
test/integration/css/test/group-2.test.js: 671.848
test/integration/i18n-support/test/index.test.js: 518.173
test/integration/scss-modules/test/index.test.js: 451.704
test/integration/css-features/test/index.test.js: 417.318
test/integration/css-modules/test/index.test.js: 403.405
test/integration/eslint/test/index.test.js: 381.563
test/integration/500-page/test/index.test.js: 371.134
test/integration/telemetry/test/index.test.js: 367.691
test/development/acceptance-app/ReactRefreshLogBox.test.ts: 335.878
test/integration/create-next-app/templates.test.ts: 334.01
test/integration/scss/test/group-2.test.js: 327.255
test/integration/scss/test/group-1.test.js: 318.574
test/integration/edge-runtime-configurable-guards/test/index.test.js: 313.834
test/e2e/instrumentation-hook/instrumentation-hook.test.ts: 294.618
test/development/acceptance-app/error-recovery.test.ts: 283.355
test/e2e/app-dir/app/vercel-speed-insights.test.ts: 278.242
test/integration/create-next-app/index.test.ts: 272.442
```
If using Server Actions on the client layer without enabling the
`serverActions` feature, the build should error. Add a test case to
ensure #50199 works.
As explained in the comments, the `cookies()` API is a mix of request and response cookies. For `.get()` methods, we want to return the request cookie if it exists. For mutative methods like `.set()`, we return the response cookie type instead.
fix#50049
fix NEXT-1211
For static member expressions like `foo.bar`, we currently treat it as one whole Ident `foo.bar` and pass it over the `$$bound` array as one value. That causes a problem where the Ident inside the function body needs to be converted, because it can no longer access to `foo`.
Closes#49985.
fix NEXT-1206
## What?
Removes `experimental.appDir` this was leftover from when I flipped the
switch.
Kept the config file as in the future we might add future flags and
such. It also helps that it has the types comment included so you always
get types.
<!-- 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 or adding/fixing 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?
Closes NEXT-
Fixes #
-->
---------
Co-authored-by: JJ Kasper <jj@jjsweb.site>
This fixes an existing bug where there're Server Actions defined in both the "server" and "client" layers (client imported Actions). They have the same worker name as they exist in one route entry, but they're built into different modules and compiled differently (server and client layers). Because of that, each route entry can have 2 "action module entries".
This PR adds the logic to differentiate that via a "layer" field so they don't conflict.
This uses the new built-in progressive enhancement features of React.
These always use `multipart/form-data` atm. When one comes in that's not
a fetch, we can use `decodeAction` to get a resolved function.
This also ensures that we can test this by passing disableJavaScript to
tests. This disables JS for the context.
Adds proper `multipart/form-data` handling in the Edge runtime and fixes a bug (previously we are always using `serverActionsManifest.node`). For the form data, we just use `await webRequest.request.formData()` for now and will handle streaming later.
For edge runtime, we're modifying `res.statusCode` in actions handler, but we didn't forward the `res` object to it, previously we're using a fake `res` `{}`. This PR fixes it so that the propery status code will be returned to the client
[slack-thread](https://vercel.slack.com/archives/C052S77L05C/p1682988777740609)
This PR renames `experimental.experimentalReact` as
`experimental.serverActions` and makes it a hard compilation error if
it's not set but detected server actions.
This PR changes `mutableCookies` from `RequestCookies` to a
`ResponseCookies` instance, and it now accepts extra options for each
cookie. Take a look at the tests for more details.
cc @styfle
---------
Co-authored-by: Steven <steven@ceriously.com>