静态预渲染
prerender 与同步字符串渲染有什么区别?
- 等待数据: prerender 在生成完整预渲染内容前等待相关数据,适合构建或预生成阶段,而非收到第一段外壳就立刻发送的实时 SSR;
- 输出载体: 成功返回 Promise 结果中的 prelude 流,不存在 result 字段;Web 与 Node 版本分别提供对应流类型;
- 可交互性: 静态预生成不意味着不能交互,输出可以由 hydrateRoot 水合;不加载客户端脚本时也能保留纯 HTML;
import { prerender } from "react-dom/static";
async function renderPage() {
const { prelude, postponed } = await prerender(<App />, {
bootstrapScripts: ["/client.js"],
});
return { htmlStream: prelude, postponed };
}
如何选择 Web 或 Node 的静态输出?
- Web Streams: prerender 返回的 prelude 可放入 Response,也可读取并写入静态文件;
- Node.js: prerenderToNodeStream 返回 Node 流形式的 prelude,使用 Node 的流消费方式;
- 文档入口: 应用通常渲染整个 html 文档,客户端脚本、模块脚本和 ID 前缀应与之后的水合入口一致;
import { prerenderToNodeStream } from "react-dom/static";
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
async function writePage(filename) {
const { prelude, postponed } = await prerenderToNodeStream(<App />);
if (postponed !== null) {
throw new Error("本次任务要求完整预渲染");
}
await pipeline(prelude, createWriteStream(filename));
}
中断后怎样保存并继续预渲染?
- 推迟状态: 未完成的预渲染可产生可序列化但不透明的 postponed,完成时该值为 null;
- 继续预生成: resumeAndPrerender 或 resumeAndPrerenderToNodeStream 接收推迟状态,继续等待并产生下一份 prelude 与 postponed;
- 请求时恢复: 如果决定在请求阶段继续,以 resume 系列实时流式恢复,区别见服务端 HTML 渲染;
静态生成怎样处理资源与安全选项?
- 资源提示: onHeaders 接收可发送的资源 Link 提示,maxHeadersLength 控制总长度;提示与 HTML 输出需要由宿主协调保存或发送;
- Import map: 使用模块脚本时可通过 importMap 配置模块标识解析,必须与实际发布路径匹配;
- Nonce 限制: 静态预渲染不接受每次请求唯一的 nonce,不能把固定 nonce 烘焙到共享静态文件中;
- 错误处理: Promise 拒绝时生成明确后备结果,onError 用于记录,不把半份未完成内容误判为完整产物;