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,
});
}