From ef830f2b5ab0ea2365457dcfbf0b5f558b07f280 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 24 Oct 2026 18:34:00 +0300 Subject: [PATCH] Render SSR with renderToReadableStream --- app/entry.server.tsx | 62 ++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 0ef515b81..4c3ffcfde 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -1,8 +1,6 @@ -import { PassThrough } from "node:stream"; -import { createReadableStreamFromReadable } from "@react-router/node"; import { isbot } from "isbot"; import cron from "node-cron"; -import { renderToPipeableStream } from "react-dom/server"; +import { renderToReadableStream } from "react-dom/server"; import { I18nextProvider } from "react-i18next"; import { type EntryContext, @@ -45,47 +43,33 @@ async function handleRequest( responseHeaders.set("Cache-Control", DEFAULT_CACHE_CONTROL); } - const callbackName = isbot(request.headers.get("user-agent")) - ? "onAllReady" - : "onShellReady"; - const instance = getI18nInstance(loadContext); - return new Promise((resolve, reject) => { - let didError = false; + let didError = false; + const body = await renderToReadableStream( + + + , + { + // +1s gives React time to flush the rejected boundary contents + signal: AbortSignal.timeout(streamTimeout + 1000), + onError(error: unknown) { + didError = true; - const { pipe, abort } = renderToPipeableStream( - - - , - { - [callbackName]: () => { - const body = new PassThrough(); - const stream = createReadableStreamFromReadable(body); - responseHeaders.set("Content-Type", "text/html"); - - resolve( - new Response(stream, { - headers: responseHeaders, - status: didError ? 500 : responseStatusCode, - }), - ); - - pipe(body); - }, - onShellError(error: unknown) { - reject(error); - }, - onError(error: unknown) { - didError = true; - - logger.error(error); - }, + logger.error(error); }, - ); + }, + ); - // +1s gives React time to flush the rejected boundary contents - setTimeout(abort, streamTimeout + 1000); + if (isbot(request.headers.get("user-agent"))) { + await body.allReady; + } + + responseHeaders.set("Content-Type", "text/html; charset=utf-8"); + + return new Response(body, { + headers: responseHeaders, + status: didError ? 500 : responseStatusCode, }); }