关于 docs-rsc-sandpack
面向 React 文档作者的 RSC Sandpack 模式指南,说明如何编写和组织 React Server Components 示例,并涵盖服务端、客户端组件及 Server Functions 的规则。
主要功能
- 01说明服务端与客户端文件指令
- 02介绍异步 Server Components 与 Suspense
- 03展示 Server Functions 模式
- 04规定入口文件与依赖限制
适用场景
- 01为文档添加 RSC 交互示例
- 02排查 Sandpack RSC 文件结构问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ reactjs/ react.dev --skill docs-rsc-sandpack安装后在 Claude Code 中输入/docs-rsc-sandpack确认已加载。
详细介绍
RSC Sandpack 模式
有关通用 Sandpack 约定(代码风格、命名、文件命名、行高亮、隐藏文件、CSS 指南),请参阅 /docs-sandpack。此技能仅介绍 RSC 特有的模式。
快速入门模板
最精简的单文件 <SandpackRSC> 示例:
<SandpackRSC>
` ` `js src/App.js
export default function App() {
return <h1>Hello from a Server Component!</h1>;
}
` ` `
</SandpackRSC>
与 <Sandpack> 的区别
| 特性 | <Sandpack> | <SandpackRSC> |
|---|---|---|
| 执行模型 | 所有代码都在 iframe 中运行 | 服务端代码在 Web Worker 中运行,客户端代码在 iframe 中运行 |
'use client' 指令 | 忽略(所有内容都是客户端代码) | 必须使用此指令标记客户端组件 |
'use server' 指令 | 不支持 | 标记可从客户端调用的服务端函数 |
async 组件 | 不支持 | 支持(服务端组件可以是异步的) |
| 外部依赖 | 支持通过 package.json 添加 | 不支持(仅支持 React 和 react-dom) |
| 入口点 | 带有 export default 的 App.js | 带有 export default 的 src/App.js |
| 组件标签 | <Sandpack> | <SandpackRSC> |
文件指令
根据文件顶部的指令对文件进行分类:
| 指令 | 运行位置 | 规则 |
|---|---|---|
| (无) | Web Worker(服务端) | 默认情况。可以是 async。可以导入其他服务端文件。不能使用 Hook、事件处理程序或浏览器 API。 |
'use client' | Sandpack iframe(浏览器) | 必须是第一条语句。可以使用 Hook、事件处理程序和浏览器 API。不能是 async。不能导入服务端文件。 |
'use server' | Web Worker(服务端) | 标记服务端函数。可用于模块级别(所有导出都是操作)或函数级别。可通过属性或表单 action 从客户端调用。 |
常见模式
1. 服务端 + 客户端组件
<SandpackRSC>
` ` `js src/App.js
import Counter from './Counter';
export default function App() {
return (
<div>
<h1>Server-rendered heading</h1>
<Counter />
</div>
);
}
` ` `
` ` `js src/Counter.js
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
` ` `
</SandpackRSC>
2. 带 Suspense 的异步服务端组件
<SandpackRSC>
` ` `js src/App.js
import { Suspense } from 'react';
import Albums from './Albums';
export default function App() {
return (
<Suspense fallback={<p>Loading...</p>}>
<Albums />
</Suspense>
);
}
` ` `
` ` `js src/Albums.js
async function fetchAlbums() {
await new Promise(resolve => setTimeout(resolve, 1000));
return ['Abbey Road', 'Let It Be', 'Revolver'];
}
export default async function Albums() {
const albums = await fetchAlbums();
return (
<ul>
{albums.map(album => (
<li key={album}>{album}</li>
))}
</ul>
);
}
` ` `
</SandpackRSC>
3. 服务端函数(操作)
<SandpackRSC>
` ` `js src/App.js
import { addLike, getLikeCount } from './actions';
import LikeButton from './LikeButton';
export default async function App() {
const count = await getLikeCount();
return (
<div>
<p>Likes: {count}</p>
<LikeButton addLike={addLike} />
</div>
);
}
` ` `
` ` `js src/actions.js
'use server';
let count = 0;
export async function addLike() {
count++;
}
export async function getLikeCount() {
return count;
}
` ` `
` ` `js src/LikeButton.js
'use client';
export default function LikeButton({ addLike }) {
return (
<form action={addLike}>
<button type="submit">Like</button>
</form>
);
}
` ` `
</SandpackRSC>
文件结构要求
入口点
- 必须有
src/App.js作为主入口点 - 必须包含
export default(函数组件) - 不区分大小写的回退:
src/app.js也可使用
自动注入的基础设施文件
这些文件由 sandpack-rsc-setup.ts 自动注入,绝不能包含在 MDX 中:
| 文件 | 用途 |
|---|---|
/src/index.js | 引导 RSC 流程 |
/src/rsc-client.js | 客户端桥接层——创建 Worker,使用 Flight 流 |
/src/rsc-server.js | 将预打包的 Worker 运行时封装为 ES 模块 |
/node_modules/__webpack_shim__/index.js | 最精简的 webpack 兼容层 |
/node_modules/__rsdw_client__/index.js | 作为本地依赖的 react-server-dom-webpack/client |
不支持外部依赖
<SandpackRSC> 不支持外部 npm 包。仅提供 react 和 react-dom。RSC 示例中不要包含 package.json。
架构参考
三层架构
react.dev page (Next.js)
┌─────────────────────────────────────────┐
│ <SandpackRSC> │
│ ┌─────────┐ ┌──────────────────────┐ │
│ │ Editor │ │ Preview (iframe) │ │
│ │ App.js │ │ Client React app │ │
│ │ (edit) │ │ consumes Flight │ │
│ │ │ │ stream from Worker │ │
│ └─────────┘ └──────────┬───────────┘ │
└───────────────────────────┼─────────────┘
│ postMessage
┌───────────────────────────▼─────────────┐
│ Web Worker (Blob URL) │
│ - React server build (pre-bundled) │
│ - react-server-dom-webpack/server │
│ - webpack shim │
│ - User server code (Sucrase → CJS) │
└─────────────────────────────────────────┘
关键源文件
| 文件 | 用途 |
|---|---|
src/components/MDX/Sandpack/sandpack-rsc/RscFileBridge.tsx | 监控 Sandpack;向 iframe 发送原始文件 |
src/components/MDX/Sandpack/SandpackRSCRoot.tsx | SandpackProvider 设置、自定义打包器 URL、UI 布局 |
src/components/MDX/Sandpack/templateRSC.ts | RSC 模板文件 |
.../sandbox-code/src/__react_refresh_init__.js | React Refresh 垫片 |
.../sandbox-code/src/rsc-server.js | Worker 运行时:模块系统、Sucrase 编译、renderToReadableStream() |
.../sandbox-code/src/rsc-client.source.js | 客户端桥接:创建 Worker、文件分类、消费 Flight 流 |
.../sandbox-code/src/webpack-shim.js | 精简的 __webpack_require__ / __webpack_module_cache__ 垫片 |
.../sandbox-code/src/worker-bundle.dist.js | 预打包的 IIFE(生成文件):React server + RSDW/server + Sucrase |
scripts/buildRscWorker.mjs | esbuild 脚本:将 rsc-server.js 打包到 worker-bundle.dist.js |
构建系统
重新构建 Worker 包
修改 rsc-server.js 或 webpack-shim.js 后:
node scripts/buildRscWorker.mjs
这会使用 esbuild,并设置:
format: 'iife'、platform: 'browser'conditions: ['react-server', 'browser'](启用 React server 导出条件)minify: true- 在输出内容前添加 webpack-shim.js
Raw-Loader 配置
在 templateRSC.js 中,文件会通过 !raw-loader 作为原始字符串加载。
这些字符串是必需的,用于将文件作为本地文件提供给 Sandpack(跳过 Sandpack 打包)。
开发命令
node scripts/buildRscWorker.mjs # Rebuild worker bundle after source changes
yarn dev # Start dev server to test examples
评论
支持 Markdown