From c113503ad131101b19b4a5c1e4639b8588ecd993 Mon Sep 17 00:00:00 2001 From: Kenta Iwasaki <63115601+lithdew@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:25:08 +0800 Subject: [PATCH] Flush direct streams in Bun (#28837) ## Summary The ReadableStreamController for [direct streams](https://bun.sh/docs/api/streams#direct-readablestream) in Bun supports a flush() method to flush all buffered items to its underlying sink. Without manually calling flush(), all buffered items are only flushed to the underlying sink when the stream is closed. This behavior causes the shell rendered against Suspense boundaries never to be flushed to the underlying sink. ## How did you test this change? A lot of changes to the test runner will need to be made in order to support the Bun runtime. A separate test was manually run in order to ensure that the changes made are correct. The test works by sanity-checking that the shell rendered against Suspense boundaries are emitted first in the stream. This test was written and run on Bun v1.1.3. ```ts import { Suspense } from "react"; import { renderToReadableStream } from "react-dom/server"; if (!import.meta.resolveSync("react-dom/server").endsWith("server.bun.js")) { throw new Error("react-dom/server is not the correct version:\n " + import.meta.resolveSync("react-dom/server")); } const A = async () => { await new Promise(resolve => setImmediate(resolve)); return
hi
; }; const B = async () => { return ( loading}> ); }; const stream = await renderToReadableStream(); let text = ""; let count = 0; for await (const chunk of stream) { text += new TextDecoder().decode(chunk); count++; } if ( text !== `
loading
` ) { throw new Error("unexpected output"); } if (count !== 2) { throw new Error("expected 2 chunks from react ssr stream"); } ``` --- packages/react-server/src/ReactServerStreamConfigBun.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react-server/src/ReactServerStreamConfigBun.js b/packages/react-server/src/ReactServerStreamConfigBun.js index ac8ae3f1a52eb..4686e0e970b12 100644 --- a/packages/react-server/src/ReactServerStreamConfigBun.js +++ b/packages/react-server/src/ReactServerStreamConfigBun.js @@ -13,6 +13,7 @@ type BunReadableStreamController = ReadableStreamController & { end(): mixed, write(data: Chunk | BinaryChunk): void, error(error: Error): void, + flush?: () => void, }; export type Destination = BunReadableStreamController; @@ -25,8 +26,12 @@ export function scheduleWork(callback: () => void) { } export function flushBuffered(destination: Destination) { - // WHATWG Streams do not yet have a way to flush the underlying - // transform streams. https://github.com/whatwg/streams/issues/960 + // Bun direct streams provide a flush function. + // If we don't have any more data to send right now. + // Flush whatever is in the buffer to the wire. + if (typeof destination.flush === 'function') { + destination.flush(); + } } export function beginWriting(destination: Destination) {}