> For AI agents: the complete documentation index is available at https://rspack.rs/zh/llms.txt, the full documentation bundle is available at https://rspack.rs/zh/llms-full.txt.

# React 服务器组件

React 服务器组件是一种新型的组件，它在打包之前，在独立于客户端应用程序或 SSR 服务器的环境中提前渲染。Rspack v2.0.0 及更高版本已内置对服务器组件的完整支持。

## 如何使用

Rspack 提供两种方案来支持 React 服务器组件：

- **使用 Rsbuild**：Rsbuild 提供对 React 服务器组件开箱即用的支持，能够快速创建一个 React 服务器组件项目，详见 [rsbuild-plugin-rsc](https://github.com/rstackjs/rsbuild-plugin-rsc)。
- **手动配置 Rspack**：你可以参考当前文档，手动添加 React 服务器组件相关的配置。

## 示例

[rstack-examples](https://github.com/rstackjs/rstack-examples/tree/main/rspack/rspack-rsc) 仓库包含了使用 Rspack 构建 React 服务器组件应用的完整示例。

## 安装依赖


```sh [npm]
npm install react react-dom react-server-dom-rspack
```

```sh [yarn]
yarn add react react-dom react-server-dom-rspack
```

```sh [pnpm]
pnpm add react react-dom react-server-dom-rspack
```

```sh [bun]
bun add react react-dom react-server-dom-rspack
```

```sh [deno]
deno add npm:react npm:react-dom npm:react-server-dom-rspack
```

:::tip
React 服务器组件依赖于 React 19 的新架构。请确保 `react` 和 `react-dom` 的版本均为 v19.1.0 或更高。
:::

## 基本概念

React 服务器组件产物需要在服务器和浏览器两种环境中协同运行。为了支持这种架构，Rspack 启动 **两个 Compiler 实例** 分别构建服务端和浏览器端的产物，下图展示了整体的构建流程：

![RSC Build Flow](https://assets.rspack.rs/rspack/assets/rspack-rsc-build-flow.jpg)

- **Client Compiler** (`target: 'web'`)： 负责生成运行在浏览器的代码。它主要打包客户端组件，以及应用所需的 CSS 和静态资源，处理组件的水合（Hydration）逻辑。
- **Server Compiler** (`target: 'node'`)： 负责生成运行在服务器的代码。它负责预渲染 React 服务器组件，并打包 Server Actions 的执行逻辑，同时处理服务端渲染（SSR）相关的代码。

在配置文件中，对应于两个 Compiler 配置：

```js title="rspack.config.mjs"
export default [
  // Client Compiler：构建浏览器端资源
  {
    target: 'web',
    // ...客户端特定配置
  },
  // Server Compiler：构建 RSC Payload 和 Server Actions
  {
    target: 'node',
    // ...服务端特定配置
  },
];
```

## 配置插件

Rspack 通过一对协同工作的插件来支持 React 服务器组件。你需要**调用一次** `rsc.createPlugins()` 得到 `ServerPlugin` 和 `ClientPlugin`，并分别挂到对应的 Compiler 上：

```js title="rspack.config.mjs"
import { experiments } from '@rspack/core';

const { createPlugins, Layers } = experiments.rsc;
const { ServerPlugin, ClientPlugin } = createPlugins();

export default [
  {
    // Client Compiler
    target: 'web',
    plugins: [new ClientPlugin()],
    // ...客户端特定配置
  },
  {
    // Server Compiler
    target: 'node',
    plugins: [new ServerPlugin()],
    // ...服务端特定配置
  },
];
```

这两个插件会在内部调度 Client Compiler 和 Server Compiler 的构建流程，同步编译状态、模块信息，生成客户端引用清单等。

## 配置构建入口

你需要分别为 Client Compiler 和 Server Compiler 配置入口。Client Compiler 中 **必须** 存在与 Server Compiler 同名的入口。

```js title="rspack.config.mjs"
export default [
  {
    target: 'web',
    entry: {
      // 必须存在与服务端同名的 'main' 入口，作为客户端 RSC 运行时的模块图根节点
      main: { import: './src/entry.client.tsx' },
    },
  },
  {
    target: 'node',
    entry: {
      // 服务端入口名称为 'main'
      main: { import: './src/entry.rsc.tsx' },
    },
  },
];
```

当 Server Compiler 在服务端代码中扫描到 `"use client"` 组件时，会把这些模块交给 Client Compiler 构建。由于 Client 侧可以配置多个入口，RSC 插件约定：**与 Server 入口同名的 Client 入口**即视为该 RSC 运行时的挂载点。

扫描到的 `"use client"` 模块会被注入到该同名入口的模块图中。若未配置同名入口，插件会报错「RSC Client Entry Mismatch」，客户端组件将无法在浏览器端正确加载。

## 配置 layer

在 Server Compiler 中，Rspack 使用 [layer](https://rspack.rs/zh/guide/advanced/layer.md) 区分 RSC 与 SSR 环境。RSC 插件使用的层名为：

- **`Layers.rsc`**（`'react-server-components'`）：RSC 环境。只有在此层下的模块，Loader 才会把 `"use client"` 转成客户端引用、把 `"use server"` 注册为 Server Action。
- **`Layers.ssr`**（`'server-side-rendering'`）：SSR 环境。用于标识 SSR 入口；若无模块被分配到此层，Rspack 会跳过 SSR 产物生成。

```js title="rspack.config.mjs"
import path from 'node:path';

const ssrEntry = path.resolve(
  import.meta.dirname,
  'src/framework/entry.ssr.tsx',
);
const rscEntry = path.resolve(
  import.meta.dirname,
  'src/framework/entry.rsc.tsx',
);

export default [
  // ...
  {
    target: 'node',
    module: {
      rules: [
        // 将 SSR 入口分配给 Layers.ssr
        {
          resource: ssrEntry,
          layer: Layers.ssr,
        },
        // 为 rsc layer 下的入口配置 resolve.conditionNames
        {
          resource: rscEntry,
          layer: Layers.rsc,
          resolve: {
            conditionNames: ['react-server', '...'],
          },
        },
        {
          issuerLayer: Layers.rsc,
          exclude: ssrEntry,
          resolve: {
            conditionNames: ['react-server', '...'],
          },
        },
      ],
    },
    // ...
  },
];
```

## 页面或路由入口

`"use server-entry"` 是 Rspack 引入的一个特有指令，主要面向框架开发者，用于将服务器组件标记为页面或路由的逻辑入口。

Rspack 编译 `"use server-entry"` 组件时，会生成浏览器初始化 RSC 应用所需的完整资源，并直接在导出的组件上挂载静态属性来记录这些信息：

- **entryJsFiles**：启动脚本。对应 Client Compiler 中同名构建入口的产物，负责在浏览器端初始化 React 运行时和渲染流程。
- **entryCssFiles**：样式资源。Rspack 会收集该服务器组件及其子服务器组件树中依赖的所有 CSS 文件。

![RSC Server Entry](https://assets.rspack.rs/rspack/assets/rspack-rsc-server-entry.jpg)

```tsx title="Todos.tsx"
'use server-entry';

import './Todos.css';
import { Dialog } from './Dialog';
import { TodoDetail } from './TodoDetail';
import { TodoCreate } from './TodoCreate';
import { TodoList } from './TodoList';

export async function Todos({ id }: { id?: number }) {
  // ...组件逻辑
}
```

在服务端运行时，你可以直接访问这些挂载在组件上的静态属性，来构建 HTML 头部资源：

```tsx title="entry.rsc.tsx"
import type { ServerEntry } from 'react-server-dom-rspack/server.node';

const { Todos } = await import('../Todos.tsx');
const serverEntry = Todos as ServerEntry<typeof Todos>;

const root = (
  <>
    {/* 读取组件上的静态属性，注入当前路由的 CSS */}
    {serverEntry.entryCssFiles
      ? serverEntry.entryCssFiles.map((href) => (
          <link
            key={href}
            rel="stylesheet"
            href={href}
            precedence="default"
          ></link>
        ))
      : null}
    <Todos id={id} />
  </>
);

const response = await handleRequest({
  request,
  getRoot: () => root,
  bootstrapScripts: serverEntry.entryJsFiles, // 读取组件上的静态属性，作为启动脚本
  nonce,
});
```

## 配置 JSX/TSX

添加 `builtin:swc-loader` 处理 `.jsx` / `.tsx`，并开启 `rspackExperiments.reactServerComponents`，以启用对 `"use client"`、`"use server"`、`"use server-entry"` 等 RSC 语法的解析与转换。

```js title="rspack.config.mjs"
const rscRule = {
  test: /\.(?:js|mjs|jsx|ts|tsx)$/,
  use: {
    loader: 'builtin:swc-loader',
    options: {
      detectSyntax: 'auto',
      rspackExperiments: {
        reactServerComponents: true,
      },
    },
  },
};

export default [
  {
    target: 'web',
    module: {
      rules: [rscRule],
    },
  },
  {
    target: 'node',
    module: {
      rules: [rscRule],
    },
  },
];
```

Loader 会根据模块所属的 layer 对 `"use client"` 和 `"use server"` 指令执行不同的转换逻辑：

1. 当模块属于 `Layers.rsc`（服务器组件环境）时，会调用 `react-server-dom-rspack` 进行转换：
   - `"use client"` 模块被转换为客户端引用（Client Reference）。
   - `"use server"` 模块被注册为 Server Action，使其能够响应来自客户端的远程调用。

2. 当模块不属于 `Layers.rsc`（如客户端或 SSR 环境）时：
   - `"use server"`：模块会转换为服务端引用（Server Reference）。

RSC 插件会依据 loader 识别出的指令信息区分客户端组件与服务器组件，并据此注入 Client 入口、收集 Server Action、生成 RSC 清单等。

## 开发服务器

RSC 需要同时处理客户端和服务器端的构建、响应 RSC 请求和服务器组件 HMR，Rspack 内置的 Dev Server 无法满足需求。你需要实现一个自定义开发服务器，以实现以下核心功能：

- **响应 RSC 请求**：拦截并处理客户端发起的 RSC 请求，调用 Server Compiler 生成的产物执行渲染逻辑，并返回序列化的 RSC Payload（或 HTML 流）。
- **服务端运行时管理**：将服务端产物运行在独立的上下文（如 Worker Threads 或子进程）中，以保证环境隔离。同时确保在服务端代码更新时，能够清理旧实例并重启以执行新代码。
- **服务器组件 HMR**：服务端组件的构建变更后，通过 WebSocket 等通信机制通知浏览器。浏览器接收到信号后，应触发 RSC 重新请求，更新页面内容。

为实现服务器组件 HMR，Rspack 在 `ServerPlugin` 中提供了 `onServerComponentChanges` 钩子（构建完成后、若有服务器组件变更则调用）。在自定义开发服务器中可在此回调里通过 WebSocket 等方式通知浏览器重新请求 RSC 以更新页面。

```js title="rspack.config.mjs"
export default [
  // ...
  {
    target: 'node',
    plugins: [
      new ServerPlugin({
        onServerComponentChanges() {
          // 调用自定义 Server 的方法通知客户端刷新
        },
      }),
    ],
  },
];
```
