1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr'
import React from 'react'
import { renderToReadableStream } from 'react-dom/server.edge'
import { prerender } from 'react-dom/static.edge'
import { injectRSCPayload } from 'rsc-html-stream/server'
import type { RscPayload } from './shared'
/**
* Server-side rendering (SSR) entrypoint for Vite RSC/SSR pipeline.
* Handles rendering of HTML streams from RSC payloads for both SSG and SSR.
*
* @param rscStream - The readable stream containing the RSC payload
* @param options - Optional options (e.g. ssg: true for static generation)
* @returns A readable stream of HTML (with injected RSC payload)
*/
export async function renderHtml(
rscStream: ReadableStream<Uint8Array>,
options?: {
ssg?: boolean
},
): Promise<ReadableStream<Uint8Array>> {
const [rscStream1, rscStream2] = rscStream.tee()
let payload: Promise<RscPayload>
function SsrRoot() {
payload ??= createFromReadableStream<RscPayload>(rscStream1)
const root = React.use(payload).root
return root
}
const bootstrapScriptContent =
await import.meta.viteRsc.loadBootstrapScriptContent('index')
let htmlStream: ReadableStream<Uint8Array>
if (options?.ssg) {
const prerenderResult = await prerender(<SsrRoot />, {
bootstrapScriptContent,
})
htmlStream = prerenderResult.prelude
} else {
htmlStream = await renderToReadableStream(<SsrRoot />, {
bootstrapScriptContent,
})
}
let responseStream: ReadableStream<Uint8Array> = htmlStream
responseStream = responseStream.pipeThrough(injectRSCPayload(rscStream2))
return responseStream
}