diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 08fdab14c86a070..ac8b5aa38195f46 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -702,7 +702,9 @@ if (process.env.__NEXT_RSC) { writer.write(encoder.encode(val)) }) buffer.length = 0 - serverDataBuffer.delete(key) + // Clean buffer but not deleting the key to mark bootstrap as complete. + // Then `nextServerDataCallback` will be safely skipped in the future renders. + serverDataBuffer.set(key, []) } serverDataWriter.set(key, writer) } diff --git a/test/integration/react-streaming-and-server-components/app/next.config.js b/test/integration/react-streaming-and-server-components/app/next.config.js index add280d239bb309..a17299bc8c9eaf2 100644 --- a/test/integration/react-streaming-and-server-components/app/next.config.js +++ b/test/integration/react-streaming-and-server-components/app/next.config.js @@ -1,6 +1,7 @@ const withReact18 = require('../../react-18/test/with-react-18') module.exports = withReact18({ + trailingSlash: true, reactStrictMode: true, onDemandEntries: { maxInactiveAge: 1000 * 60 * 60, diff --git a/test/integration/react-streaming-and-server-components/app/pages/streaming-rsc.server.js b/test/integration/react-streaming-and-server-components/app/pages/streaming-rsc.server.js new file mode 100644 index 000000000000000..ac58f5e9e2c382c --- /dev/null +++ b/test/integration/react-streaming-and-server-components/app/pages/streaming-rsc.server.js @@ -0,0 +1,23 @@ +import { Suspense } from 'react' + +let result +let promise +function Data() { + if (result) return result + if (!promise) + promise = new Promise((res) => { + setTimeout(() => { + result = 'next_streaming_data' + res() + }, 500) + }) + throw promise +} + +export default function Page() { + return ( + + + + ) +} diff --git a/test/integration/react-streaming-and-server-components/test/rsc.js b/test/integration/react-streaming-and-server-components/test/rsc.js index 604073c3930fd8e..a01fefe5eb1d605 100644 --- a/test/integration/react-streaming-and-server-components/test/rsc.js +++ b/test/integration/react-streaming-and-server-components/test/rsc.js @@ -82,6 +82,12 @@ export default function (context, { runtime, env }) { expect(await browser.eval('window.beforeNav')).toBe(1) }) + it('should handle streaming server components correctly', async () => { + const browser = await webdriver(context.appPort, '/streaming-rsc') + const content = await browser.eval(`window.document.body.innerText`) + expect(content).toMatchInlineSnapshot('"next_streaming_data"') + }) + // Disable next/image for nodejs runtime temporarily if (runtime === 'edge') { it('should suspense next/image in server components', async () => {