Commit Graph

40 Commits

Author SHA1 Message Date
Niklas Mischkulnig bdbf63aef7 fix(next-custom-transforms): never place generated imports before directives (#98717)
## 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>
2026-09-16 17:09:32 +02:00
Hendrik Liebau c0c64a0ab1 Allow literal exports in 'use cache' files (#97181) 2026-08-12 06:42:24 +02:00
Jiachi Liu 3aad67b75c feat: server action logging (#88277) 2026-01-16 15:09:02 +01:00
Hendrik Liebau 3d30f407c4 Allow exporting object and array literals in 'use cache' files again (#86655)
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.
2025-12-01 10:01:11 +01:00
Hendrik Liebau 59fe222b5e Convert any export from a 'use cache' module to a cache function (#86014)
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
2025-11-26 15:30:25 +01:00
Hendrik Liebau acac0b0567 Fix compilation of exported server functions (#86296)
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 '📙' }

```
2025-11-24 13:54:17 +01:00
Niklas Mischkulnig 33e1764252 Bump swc to 48 (#86240)
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~~
2025-11-21 12:47:13 +01:00
Hendrik Liebau ee6e35a19e Omit unused encryptActionBoundArgs/decryptActionBoundArgs imports (#86015)
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.
2025-11-12 11:19:09 +01:00
Hendrik Liebau ba20a5e8f2 Fix false-positive build error for cacheLife & cacheTag (#85875)
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
2025-11-11 17:30:41 +01:00
Hendrik Liebau b6a7714057 Hoist inner 'use cache' functions to reduce function allocations (#85904)
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.
2025-11-10 13:09:59 +01:00
Zack Tanner da024c190a [cache components] move experimental.cacheHandlers out of experimental (#85157)
Moves this flag out of experimental so that custom `use cache` handlers
can be configured alongside the cache components release.
2025-10-21 10:41:28 -07:00
Hendrik Liebau 81bccc93e9 Guide users to experimental.cacheComponents config (#84121)
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
2025-09-23 12:23:59 +02:00
Hendrik Liebau 99b078b8da Emit build error when 'use cache' directive is misspelled (#83756)
Handles cases like:
- `'use cache:remote'` (missing space after colon)
- `'use cache : default'` (extra space before colon)
- `'use cache private'` (missing colon)
- `'use cache: '` (missing cache kind)

closes NAR-392
2025-09-13 20:59:39 +02:00
Hendrik Liebau 08209b9bf4 Improve error message for sync server functions (#81705)
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
2025-07-16 13:33:20 +02:00
Joseph 74be505943 Update help link for inlined use server in client components (#81495)
Partially Closes:
https://linear.app/vercel/issue/DOC-4854/server-actions-v14-and-v13-links
2025-07-14 07:36:55 +00:00
Hendrik Liebau 4d3a02d86f Allow server functions to be used as client component props in 'use cache' (#81431)
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
2025-07-09 15:41:15 +02:00
Donny/강동윤 3a30312049 refactor(actions): Remove turbopack magic comments (#77063)
### 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.
2025-03-14 15:27:55 +09:00
Janka Uryga 03a600c5b8 fix: workaround for TS bug in Object.defineProperty (#75944)
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.
2025-02-25 15:30:03 +00:00
Hendrik Liebau 847506f716 Emit build error if 'use action' directive is used (#74954) 2025-01-16 01:07:46 +01:00
Hendrik Liebau 214e0d3252 Forbid super in static class methods with server function directives (#73061) 2024-11-26 19:19:16 +01:00
Hendrik Liebau 12c483aa4d Don't hoist a server function if a compile error was emitted (#73189)
This allows us to skip unnecessary work, and also avoids generating invalid code, e.g. not allowed `super` calls in hoisted methods.
2024-11-26 17:24:10 +01:00
Hendrik Liebau 6602327c72 Handle server function directives in class methods (#73060)
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.
2024-11-25 15:26:24 +01:00
Hendrik Liebau adfdd09d53 Omit unnecessary cache wrapper import (#73160)
When a `"use cache"` module has no exported or annotated cache function, we can omit the import statement for the cache wrapper function.
2024-11-25 15:00:38 +01:00
Hendrik Liebau c53ee73cf1 Forbid this and arguments in server functions (#73059)
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>
2024-11-23 23:46:24 +01:00
Hendrik Liebau 04adb76405 Disallow multiple server directives at the same level (file or function) (#73018)
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.
2024-11-22 21:35:44 +01:00
Donny/강동윤 c8f96d50ff perf(turbopack): Enable merging of export fragments (#72813)
### 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
2024-11-21 23:06:41 +09:00
Hendrik Liebau 44cb7dddfe Consolidate FnExpr and FnDecl server function transforms (#72960)
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
2024-11-20 09:07:01 +01:00
Hendrik Liebau d54122a712 Emit build error for unknown cache kinds (#72832)
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>
2024-11-17 17:03:16 +01:00
Hendrik Liebau 0f9f442b7b Consolidate server actions transform errors into emit_error function (#72811)
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.
2024-11-15 13:55:19 +01:00
Shu Ding ba9879bf98 Implement information byte in Server Reference ID and other optimizations (#71463)
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.
2024-10-28 04:16:20 +01:00
Hendrik Liebau 0a916775d5 Allow "use cache" functions in server action module (client layer) (#71511)
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.
2024-10-19 17:58:58 +02:00
Hendrik Liebau 8c401f6964 Differentiate error messages in server function transforms (#71491)
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.`
2024-10-19 01:33:03 +02:00
Hendrik Liebau c54b8a3a36 Assign proper function names to server actions (#71478)
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.
2024-10-19 00:53:21 +02:00
Hendrik Liebau 8dfb58f8fe Skip unnecessary work in server action transforms for client modules (#71417)
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.
2024-10-17 17:22:41 +00:00
Shu Ding f6afb0e09e Fix SWC cache transform on the client layer (#71095)
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.
2024-10-10 19:03:14 +00:00
Hendrik Liebau 5975ae0e5d Unwrap registerServerReference function (#70563)
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.
2024-10-04 13:09:03 +02:00
Shu Ding 5c235de03f Improve the RSC directive transform (#70562)
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.
2024-09-28 02:03:10 +00:00
Shu Ding 2fc641efb6 Unwrap createServerReference, and pass additional parameters (#69190)
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>
2024-09-27 07:52:21 +02:00
Shu Ding bd19545a7d Improve server directive SWC transform (#70257) 2024-09-22 19:24:57 +02:00
hrmny cad3a51049 refactor: move rust crates to the repo root directory (#67780)
### Why?
In preparation for moving all turbopack crates

Also makes them easier to work with in general.

Closes PACK-3164
2024-07-22 18:41:27 +02:00