276 - 《手撕源码 30:wakuwork 和 RSC 原理》
发布于 2023年3月21日
手撕 wakuwork 之前,我们先理解下 React Server Components,下面简称为 RSC 。
我们以一个具体例子来看 RSC 的实现。比如有两个文件,app.tsx 和 foo.tsx,其中 foo.tsx 加了 "use client"
的标记,所以 app.tsx 应该在 server 端渲染,foo.tsx 应该在 client 端渲染。
import { Foo } from './foo';
export function App() {
return <><h1>App</h1><Foo /></>
}
"use client";
export function Foo() {
return <div>Foo</div>;
}
1、当用户访问应用时,需要通知 server 渲染 App 组件,拿到 App 组件的流式数据后拼成 React 组件需要的数据格式,最终渲染到页面里。
import ReactDOM from 'react-dom/client';
import { createFromFetch } from 'react-server-dom-webpack/client';
// 从 server 拿 App 组件的数据
// rsc 表示 react server components
const response = fetch('/?rsc_id=App&props=...');
const options = {};
// 基于 response 创建 React 组件
const data = await createFromFetch(response, options);
// 渲染组件到页面
ReactDOM.createRoot(document.getElementById('root')).render(data);
2、server 在处理 /?rsc_id=App&props=…
时做了什么?又返回了什么数据?
node-register 的实现见 react/ReactFlightWebpackNodeRegister.js,针对 "use client"
和 "use server"
分别处理,返回额外的 id、typeof、bound 等元信息。
// 注册 node register,处理 "use client" 和 "use server"
const RSDWRegister = require('react-server-dom-webpack/node-register');
RSDWRegister();
const bundleConfig = new Proxy({}, {
get(target, id) {
const [filePath, name] = id.split("#");
return {
id, chunks: