You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用renderToPipeableStream时如何注入Vite插件预编译代码?

Vite + React SSR + Suspense 流式渲染实现方案

核心思路

先通过Vite处理完index.html模板,拆分出静态片段后,再结合renderToPipeableStream分阶段流式输出内容,既保留Vite的模板转换能力,又实现React的增量流式渲染。

具体步骤与代码实现

  1. 预处理模板并拆分片段
    先调用Vite的transformIndexHtml拿到已注入预编译代码的完整模板,将其拆分为「头部静态内容」「SSR占位符前缀」「尾部静态内容」三部分,避免流式渲染时无法处理模板转换的问题。

  2. 分阶段流式输出
    先向客户端发送处理好的静态头部和占位符前缀,再启动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'));
  1. 客户端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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:17:47