## Summary
**What?** Fixes the error reported for a module that has a top-level
`"use client"` directive and an inline `"use server"` function
directive, e.g. `<form action={async () => { "use server" }} />` in a
client page.
**Why?** Under Turbopack this reported a bogus error — `The "use client"
directive must be placed before other expressions` — even though the
directive was already at the top of the file. The actual mistake (an
inline server action inside a Client Component) was never surfaced.
**How?** On Turbopack's RSC layer the server actions transform runs
*before* the React Server Components assert. When it hoists an inline
action it prepended its generated imports (`registerServerReference`,
action encryption, cache runtime) at index 0 of the module — *above* the
`"use client"` directive, which the transform does not consume. The RSC
assert then saw an import before the directive and reported it as
misplaced.
Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
In #86014 we added a validation for exporting object and array literals
from `'use cache'` files. This was a bit too restrictive, and
short-sighted, as it would prevent exporting common things like metadata
or viewport objects from page and layout files, if the file uses a `'use
cache'` top-level directive.
Previously, in a `'use cache'` module, we only compiled statically-known
exported functions and arrow expressions to cache functions. Now, we
also compile re-exports and exports of values that might be functions.
This includes exports like:
- `export { getData } from './data'` - re-exporting from another module
- `export const aliased = getData` - exporting an imported identifier
- `const Page = withSlug(...); export default Page` - exporting the
result of a function call
These cases can't be statically verified as functions at compile time,
so we generate runtime wrappers with `typeof === "function"` checks
(simplified):
```js
let $$RSC_SERVER_CACHE_getData = getData;
if (typeof getData === "function") {
$$RSC_SERVER_CACHE_getData = React.cache(function() {
return cache("default", "...", 0, getData, arguments);
});
registerServerReference($$RSC_SERVER_CACHE_getData, "...", null);
Object.defineProperty($$RSC_SERVER_CACHE_getData, "name", { value: "getData" });
}
export { $$RSC_SERVER_CACHE_getData as getData };
```
This ensures that all function exports from `'use cache'` modules are
properly cached, while non-function exports pass through unchanged.
This approach comes with some limitations compared to statically-known
function exports:
1. **No compile-time type checking:** We can't verify that these exports
are actually functions. Non-function exports will be passed through
as-is at runtime.
2. **No async enforcement:** We can't enforce that functions must be
async (as we do for statically-known functions). Synchronous functions
are supported, but will lie about their type signature. They become
async after being wrapped as cache functions, even though their original
signature was synchronous.
closes NAR-196
With this PR we are restructuring how the Next.js compiler transforms server function modules (`'use server'` or `'use cache'` directive at the top of the file).
The workaround for skipping the registration of exported `'use cache'` functions is removed. All exported server functions are now properly registered during visitor traversal, which fixes incorrect server reference information bytes in server reference IDs in some circumstances (see #86292 for example).
We're also adding support for string literal exports, e.g.:
```js
'use server'
async function foo() {}
export { foo as '📙' }
```
Upgrade swc from 45 to 48
Based on #85540
- In the AST, strings now contain a `Wtf8Atom` (= not utf8), while `Ident`s keep using the utf8 `Atom`.
- swc's comment printing logic also changed slighted, moving some comments around
- ~~Some comments are getting lost along the way and/or attached to the wrong line. This also broke server actions which rely on a `__next_internal_client_entry_do_not_use__` at the very top~~
When a module does not include any `'use server'` or `'use cache'` closures that use variables from their outer scope, the imports for `encryptActionBoundArgs` and `decryptActionBoundArgs` are unnecessary.
> [!TIP]
> Review with hidden whitespace changes.
When functions exported from a module with a top-level `'use cache'`
directive are imported into client modules, the compiler should allow
`cacheLife` and `cacheTag` usage within those functions.
This PR updates the `react_server_components` transform to properly
track module directives (`'use client'`, `'use server'`, `'use cache'`)
and skip client graph validation for modules with `'use cache'`,
identical to how modules with `'use server'` are already handled. Those
modules are transformed anyway for the client graph by the
`server_actions` transform, which is applied after the
`react_server_components` transform, in which their implementation is
replaced by server function references.
closes NAR-498
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.
In error messages and in docs for `'use cache'` and related APIs, we now
guide users to the `experimental.cacheComponents` config instead of
`experimental.useCache`.
closes NAR-410
When a server action or `'use cache'` function is defined as a
synchronous function, the error message now only marks the function name
for better clarity. Previously, the entire function body was marked,
which looks fine in small test fixtures, but is pretty messy for larger
functions, both in the terminal as well as in the dev error overlay.
For anonymous default exports we can't optimize this and are still
marking the entire function body, as we don't have a name to refer to.
closes NAR-165
When passing server actions or nested `'use cache'` functions inside of
cached components as props to client components, we need to make sure
that those are registered as server references, even when restoring the
parent component from the cache, e.g. during the resume of a partially
static shell. Otherwise, React would throw a runtime error while trying
to serialize the props.
<details>
<summary>Example</summary>
```tsx
import { connection } from 'next/server'
import { Suspense } from 'react'
export default function Page() {
return (
<div>
<Suspense fallback={<h1>Loading...</h1>}>
<Dynamic />
</Suspense>
<CachedForm />
</div>
)
}
const Dynamic = async () => {
await connection()
return <h1>Dynamic</h1>
}
async function CachedForm() {
'use cache'
return (
<form
action={async () => {
'use server'
console.log('Hello, World!')
}}
>
<button>Submit</button>
</form>
)
}
```
</details>
Previously, for inline server functions, the Next.js compiler placed the
`registerServerReference` calls where the server function was originally
declared. When the enclosing function was restored from a cache, this
call was skipped and the reference was not registered, leading to the
serialization error. To fix it, we can hoist the
`registerServerReference` call into the module scope, where the
reference itself also has been hoisted to. For simplicity, we're doing
this now generally, regardless of whether the server function is inline
or top-level.
Note: Since `registerServerReference` uses `Object.defineProperties` to
mutate the given reference, we don't need to assign the result to
anything. We already did this for exported functions of a module with a
top-level `'use server'` directive.
closes NAR-167
### What?
Remove magic comments for disabling export merging in the advanced tree shaking of turbopack.
### Why?
Turbopack magic comments for tree shaking + server actions are not required anymore since https://github.com/vercel/next.js/pull/76938.
This PR changes the server action generated code a bit to work around a
typescript bug and remove some false positives we got while
typechecking: https://github.com/microsoft/TypeScript/issues/61165
The trick is that typescript seems to look for *exactly*
`Object.defineProperty(obj, 'literal', { value: ... })`, and changing
any part of the expression bypasses the bug, so we can just use
`Object['defineProperty']` instead.
With this PR, we are allowing _static_ class methods to be annotated with `"use cache"` or `"use server"`.
Class _instance_ methods on the other hand are not allowed as server functions.
Accessing `this` or `arguments` in server functions is not allowed. With
this PR, we are now emitting build errors in this case.
---------
Co-authored-by: Janka Uryga <lolzatu2@gmail.com>
This PR has two main goals:
- **Consolidate the detection of server directives in modules and function bodies.** Previously, these were two separate implementations with significant overlap, but also some [questionable discrepancies](https://github.com/vercel/next.js/pull/72811#discussion_r1843660381).
- **Model the current directive (in a file or function) using an enum instead of two separate booleans.** This change prevents any confusion that both directives might be present simultaneously. Additionally, we're now emitting an error if multiple directives (`"use server"` and `"use cache"`) are defined in the same location (at the top of a file or function body).
A mixed usage of `"use server"` and `"use cache"` _across different locations_ is still allowed, e.g. `"use cache"` at the top of a file, and `"use server"` in a function.
> [!NOTE]
> The diff may be tricky to review because chunks from two different functions are combined into a single function. Fortunately, we have comprehensive test coverage for the transforms, which instills high confidence that these changes are correct.
### What?
Enable single-incoming-edge optimization for module fragments with `ModulePart::Export`.
### Why?
It will reduce the number of modules greatly.
### How?
Closes PACK-3481
By adding `visit_mut_function` we can deduplicate the code that's common between `visit_mut_fn_expr` and `visit_mut_fn_decl`. And more importantly, this prepares us for handling the transform of method props, which will also use `visit_mut_function`.
As a positive side effect this brings two small improvements with it:
- always highlight the whole function when `async` is missing, not only the identifier
- assign a function name to an anonymous arrow function expression in a variable declaration
When a `"use cache"` directive with a custom cache kind is used, e.g.
`"use cache: custom"`, a cache handler with the same name must be
specified in the Next.js config:
```js
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
experimental: {
dynamicIO: true,
cacheHandlers: {
custom: require.resolve('path/to/custom/cache/handler'),
},
},
}
module.exports = nextConfig
```
If this is not the case, we emit a build error with an error message
that explains this requirement.
<img width="795" alt="Screenshot 2024-11-14 at 23 30 01"
src="https://github.com/user-attachments/assets/bd138c97-608f-42ce-abb2-edb3e44edc3f">
When we'll get a docs page for this experimental config, we will add the
usual "Read more: ..." hint as well.
---------
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Co-authored-by: Janka Uryga <lolzatu2@gmail.com>
This improves maintainability and readability by decluttering the server actions transforms implementation, dedupes a few error messages, and consistently uses periods and trailing newlines for all error messages.
The same approach is already used for the React Server Components transforms.
With this PR, we're adding one extra leading byte to Server Reference
IDs (both Server Actions and `"use cache"` functions), to include some
static information about the function itself.
The information byte has the following format:
```
0 000000 0
^type ^arg mask ^rest args
```
The type bit represents if the action is a cache function or not. For
cache functions, the type bit is set to `1`. Otherwise, it's `0`.
The arg mask bit is used to determine which arguments are used by the
function itself, up to 6 arguments. The bit is set to `1` if the
argument is used, or being spread or destructured (so it can be
indirectly or partially used). The bit is set to `0` otherwise.
The rest args bit is used to determine if there's a `...` rest argument
in the function signature. If there is, the bit is set to `1`.
For example:
```tsx
async function foo(a, foo, b, bar, ...baz) {
'use cache';
return a + b;
}
```
will have it encoded as `[1][101011][1]`. The first bit is set to `1`
because it's a cache function. The second part has `1010` because the
only arguments used are `a` and `b`. The subsequent `11` bits are set to
`1` because there's a `...baz` argument starting from the 5th. The last
bit is set to `1` as well for the same reason.
Note: Currently in this PR we don't track if an argument is actually
referenced in the function body or not. That will be implemented as a
follow-up optimization.
Also, the reference ID is currently hex-encoded so there will be exact 2
characters for easier decoding. This encoding might change though.
With this extra byte, the client can do some further optimizations. More
details can be found in the code comment.
When importing a server action module from a client component, we've
already opted into the server layer, so defining inline `"use cache"`
annotated functions should be allowed.
Updated error messages to differentiate between the two different directives.
### `"use server"`
- `Server Actions must be async functions.`
- `Only async functions are allowed to be exported in a "use server" file.`
### `"use cache"`
- `"use cache" functions must be async functions.`
- `Only async functions are allowed to be exported in a "use cache" file.`
This PR adjusts the server action transforms to assign proper function names for the generated server reference proxies.
- If the original function has a name, this name is used.
- If a function expression is assigned to a variable, the variable's name is used.
- If an anonymous function expression is assigned to a prop, the prop's name is used.
In addition, this PR simplifies the output for exported functions, avoiding unnecessary `registerServerReference` calls.
It also fixes the source mapping of default exported server actions.
**Before:**
<img width="890" alt="before" src="https://github.com/user-attachments/assets/a3d6a5f8-d48e-474d-8f03-b49306fb704f">
**After:**
<img width="890" alt="after" src="https://github.com/user-attachments/assets/8f332690-6c26-46f1-9eef-7680f47ea578">
Next up, we will do the same for `'use cache'` functions.
The hoisting of the proxy expressions only needs to be done for the
server layer. We can skip this part completely when we know we're
compiling a module for the client layer.
This PR fixes the cache function transform on the client layer, which
should be transpiled into a Server Reference with proper sourcemap
parameters, similar to Server Actions.
In the same vein as #69190, where we already unwrapped `createServerReference`, we now also unwrap `registerServerReference`, which is required for React to select the right call stack frame when generating source locations for server actions (see facebook/react#30741).
Whereas unwrapping of `createServerReference` was required for server actions that are imported into client components, unwrapping `registerServerReference` is needed for server actions that are passed from server components to client components.
This does not fully enable the source mapping just yet. For this to work end-to-end, the next step is to generate proper spans in the SWC transform, which will be done in the next PR.
This PR extends the cache directive to accept an additional type
parameter which defaults to `"default"`.
Several follow-ups:
- Accept different syntaxes (like places of spaces) and typo detection;
- Have a limited set of valid options with better errors.
For https://github.com/facebook/react/pull/30741
This PR adds several additional parameters to the
`createServerReference` calls generated by the Server Reference SWC
transform, to later enable React to map server actions that are imported
into client components back to their server locations (dev mode only).
Currently the inner `findSourceMapURL` function is not yet implemented.
In a follow-up we will unwrap `registerServerReference` as well, which
is needed for server actions in the react server layer.
---------
Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>