diff --git a/packages/plugin-rsc/examples/ssg/src/framework/entry.rsc.tsx b/packages/plugin-rsc/examples/ssg/src/framework/entry.rsc.tsx index d0d9d2354..6af940baa 100644 --- a/packages/plugin-rsc/examples/ssg/src/framework/entry.rsc.tsx +++ b/packages/plugin-rsc/examples/ssg/src/framework/entry.rsc.tsx @@ -36,3 +36,27 @@ export default async function handler(request: Request): Promise { }, }) } + +// return both rsc and html streams at once for ssg +export async function handleSsg(request: Request): Promise<{ + html: ReadableStream + rsc: ReadableStream +}> { + const url = new URL(request.url) + const rscPayload: RscPayload = { root: } + const rscStream = ReactServer.renderToReadableStream(rscPayload) + const [rscStream1, rscStream2] = rscStream.tee() + + const ssr = await import.meta.viteRsc.loadModule< + typeof import('./entry.ssr') + >('ssr', 'index') + const htmlStream = await ssr.renderHtml(rscStream1, { + ssg: true, + }) + + return { html: htmlStream, rsc: rscStream2 } +} + +if (import.meta.hot) { + import.meta.hot.accept() +} diff --git a/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx index 449c6ca21..d5ee6264d 100644 --- a/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx @@ -4,7 +4,12 @@ import * as ReactDomServer from 'react-dom/server.edge' import { injectRSCPayload } from 'rsc-html-stream/server' import type { RscPayload } from './shared' -export async function renderHtml(rscStream: ReadableStream) { +export async function renderHtml( + rscStream: ReadableStream, + options?: { + ssg?: boolean + }, +) { const [rscStream1, rscStream2] = rscStream.tee() let payload: Promise @@ -20,8 +25,9 @@ export async function renderHtml(rscStream: ReadableStream) { const htmlStream = await ReactDomServer.renderToReadableStream(, { bootstrapScriptContent, }) - // for SSG - await htmlStream.allReady + if (options?.ssg) { + await htmlStream.allReady + } let responseStream: ReadableStream = htmlStream responseStream = responseStream.pipeThrough(injectRSCPayload(rscStream2)) diff --git a/packages/plugin-rsc/examples/ssg/vite.config.ts b/packages/plugin-rsc/examples/ssg/vite.config.ts index b84ad62f3..c66088463 100644 --- a/packages/plugin-rsc/examples/ssg/vite.config.ts +++ b/packages/plugin-rsc/examples/ssg/vite.config.ts @@ -1,4 +1,3 @@ -import assert from 'node:assert' import fs from 'node:fs' import path from 'node:path' import { Readable } from 'node:stream' @@ -60,29 +59,24 @@ async function renderStatic(config: ResolvedConfig) { // render rsc and html const baseDir = config.environments.client.build.outDir - for (const htmlPath of staticPaths) { - config.logger.info('[vite-rsc:ssg] -> ' + htmlPath) - const rscPath = htmlPath + RSC_POSTFIX - const htmlResponse = await entry.default( - new Request(new URL(htmlPath, 'http://ssg.local')), + for (const staticPatch of staticPaths) { + config.logger.info('[vite-rsc:ssg] -> ' + staticPatch) + const { html, rsc } = await entry.handleSsg( + new Request(new URL(staticPatch, 'http://ssg.local')), ) - assert.equal(htmlResponse.status, 200) - await fs.promises.writeFile( - path.join(baseDir, normalizeHtmlFilePath(htmlPath)), - Readable.fromWeb(htmlResponse.body as any), - ) - - const rscResponse = await entry.default( - new Request(new URL(rscPath, 'http://ssg.local')), - ) - assert.equal(rscResponse.status, 200) - await fs.promises.writeFile( - path.join(baseDir, rscPath), - Readable.fromWeb(rscResponse.body as any), + await writeFileStream( + path.join(baseDir, normalizeHtmlFilePath(staticPatch)), + html, ) + await writeFileStream(path.join(baseDir, staticPatch + RSC_POSTFIX), rsc) } } +async function writeFileStream(filePath: string, stream: ReadableStream) { + await fs.promises.mkdir(path.dirname(filePath), { recursive: true }) + await fs.promises.writeFile(filePath, Readable.fromWeb(stream as any)) +} + function normalizeHtmlFilePath(p: string) { if (p.endsWith('/')) { return p + 'index.html'