430 - 《RSC》

发布于 2024年4月14日

近期要做 RSC 的支持,再看了一遍相关文档,整理如下。

1、生成 RSC 协议字符串。

比如我们有个组件树,App -> Foo。调 RSDWS(react-server-dom-webpack/server) 渲染 App 即可得到 RSC 协议的字符串。

import rsdws from "react-server-dom-webpack/server";
const { renderToPipeableStream } = rsdws;
import { App } from "./app/App.js";
renderToPipeableStream(<App />).pipe(process.stdout);

// 输出
// J0:["$","div",null,{"children":[["$","h1",null,{"children":"App"}],["$","p",null,{"children":"Foo"}]]}]

现在来加一个 Client 组件 Bar,注意 Client 组件在 RSC render 时不会引真实文件,而是被替换成 { $$typeof, filepath, name } 的格式。这一步通常由框架或构建工具来做。然后 renderToPipeableStream 时加上 bundle 相关配置,webpack 的场景下需要 id、name 和 chunks 字段。

const Bar = {
  $$typeof: Symbol.for("react.module.reference"),
  filepath: "Bar.tsx",
  name: "Bar",
};
renderToPipeableStream(<App />, { 'Bar.tsx': { Bar: { id: 'Bar.tsx', name: 'xxx', chunks: [] } } }).pipe(process.stdout);

// 输出
// M1:{"id":"Bar.tsx","name":"xxx", "chunks":[]}
// J0:["$","div",null,{"children":[["$","h1",null,{"children":"App"}],["$","p",null,{"children":"Foo"}],["$","@1",null,{}]]}]

其中 Mx 表示模块,而 ["$","@1",null,{}] 表示使用 M1 模块。

2、react-server condition。

基于 0227-server-module-conventions,前面的代码要跑起来,是需要加 --conditions react-server 的,比如 node --conditions react-server /path/to/file.js。原因是 react-server-dom-webpack 的 package.json 中 server 有 react-server 的 condition

一个好处是,如果错误地在 RSC 中使用 useState、useEffect 等不支持的 hooks,由于根本没这个 export,会直接报错。

file:///private/tmp//Foo.js:2
import { useEffect, useState } from "react";
         ^^^^^^^^^
SyntaxError: Named export 'useEffect' not found. The requested module 'react' is a CommonJS module, which may not support all module.exports as na

内容预览已结束

此内容需要会员权限。请先登录以查看完整内容。