使用renderToPipeableStream时如何注入Vite插件预编译代码?
Vite + React SSR + Suspense 流式渲染实现方案
核心思路
先通过Vite处理完index.html模板,拆分出静态片段后,再结合renderToPipeableStream分阶段流式输出内容,既保留Vite的模板转换能力,又实现React的增量流式渲染。
具体步骤与代码实现
预处理模板并拆分片段
先调用Vite的transformIndexHtml拿到已注入预编译代码的完整模板,将其拆分为「头部静态内容」「SSR占位符前缀」「尾部静态内容」三部分,避免流式渲染时无法处理模板转换的问题。分阶段流式输出
先向客户端发送处理好的静态头部和占位符前缀,再启动React流式渲染输出组件内容,最后补全尾部静态内容,完成整个HTML的拼接。
以Express服务器为例:
import express from 'express'; import fs from 'fs'; import path from 'path'; import { renderToPipeableStream } from 'react-dom/server'; import { App } from './src/App'; import vite from 'vite'; const app = express(); const viteServer = await vite.createServer({ server: { middlewareMode: true }, }); app.use(viteServer.middlewares); app.get('*', async (req, res) => { try { // 读取原始index.html并通过Vite完成模板转换 const rawTemplate = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf-8'); const processedTemplate = await viteServer.transformIndexHtml(req.url, rawTemplate); // 拆分模板为三个部分(根据你的实际模板结构调整拆分规则) const templateSplit = processedTemplate.split(/(<div id="root">|<\/div>)/); const headContent = templateSplit[0]; const rootPrefix = templateSplit[1]; const tailContent = templateSplit[2] + templateSplit[3]; // 设置响应头,开启流式传输 res.setHeader('Content-Type', 'text/html'); // 先发送静态头部和根节点前缀 res.write(headContent + rootPrefix); // 启动React流式渲染 const { pipe, abort } = renderToPipeableStream(<App />, { onShellReady() { // 开始流式输出React渲染内容 pipe(res); }, onShellError(err) { res.status(500).send('Server Render Error'); abort(); }, onAllReady() { // 渲染完成后发送尾部静态内容,结束响应 res.write(tailContent); res.end(); }, onError(err) { console.error('SSR Error:', err); }, }); } catch (err) { viteServer.ssrFixStacktrace(err); res.status(500).send(err.stack); } }); app.listen(3000, () => console.log('Server running on port 3000'));
- 客户端Hydration适配
客户端需使用hydrateRoot配合流式渲染,确保与服务端输出的内容正确对接:
import { hydrateRoot } from 'react-dom/client'; import { App } from './App'; hydrateRoot(document.getElementById('root'), <App />);
关键注意事项
- 模板拆分规则需与你的
index.html结构匹配,确保拆分后的片段拼接后是完整合法的HTML。 - Vite的
transformIndexHtml已自动注入React预编译代码和客户端脚本,这些内容会包含在headContent中,无需额外处理即可避免预编译代码缺失的错误。
内容的提问来源于stack exchange,提问作者Moritz Roessler
相关产品推荐
相关产品推荐

