From 00af6025aecf24f19784cf6b1ba7d9e92ee04a56 Mon Sep 17 00:00:00 2001 From: Hendrik Liebau Date: Tue, 21 May 2024 18:59:25 +0200 Subject: [PATCH 1/2] [Flight] Add failing test for dedupe resolution on blocked models Triggered by https://github.com/vercel/next.js/pull/66033 I was suspecting that the bug was introduced with #28996, but I could not make the test succeed on a commit before that PR, so maybe this assumption is wrong. --- .../__tests__/ReactFlightDOMBrowser-test.js | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index d0630287dbf8b..e9bdc4b6db33d 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -247,6 +247,55 @@ describe('ReactFlightDOMBrowser', () => { expect(container.innerHTML).toBe('Hello, World!'); }); + it('should resolve deduped objects within the same model root when it is blocked', async () => { + let resolveClientComponentChunk; + + const ClientOuter = clientExports(function ClientOuter({Component, value}) { + return ; + }); + + const ClientInner = clientExports( + function ClientInner({value}) { + return
{JSON.stringify(value)}
; + }, + '42', + '/test.js', + new Promise(resolve => (resolveClientComponentChunk = resolve)), + ); + + function Server({value}) { + return ; + } + + const shared = [1, 2, 3]; + const value = [shared, shared]; + + const stream = ReactServerDOMServer.renderToReadableStream( + , + webpackMap, + ); + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromReadableStream(stream); + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(); + }); + + expect(container.innerHTML).toBe(''); + + await act(() => { + resolveClientComponentChunk(); + }); + + expect(container.innerHTML).toBe('
[[1,2,3],[1,2,3]]
'); + }); + it('should progressively reveal server components', async () => { let reportedErrors = []; From e56dc0b99876d3ba2fe45b066d5d9a5454d7b51b Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Tue, 21 May 2024 13:53:04 -0400 Subject: [PATCH 2/2] Don't clear pending listeners when entering blocked state The cyclic state might have added listeners that will still need to be invoked. --- packages/react-client/src/ReactFlightClient.js | 2 -- packages/react-server/src/ReactFlightReplyServer.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 3129437fa4332..6e4d28c5e907d 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -506,8 +506,6 @@ function initializeModelChunk(chunk: ResolvedModelChunk): void { // We have to go the BLOCKED state until they're resolved. const blockedChunk: BlockedChunk = (chunk: any); blockedChunk.status = BLOCKED; - blockedChunk.value = null; - blockedChunk.reason = null; } else { const resolveListeners = cyclicChunk.value; const initializedChunk: InitializedChunk = (chunk: any); diff --git a/packages/react-server/src/ReactFlightReplyServer.js b/packages/react-server/src/ReactFlightReplyServer.js index 27ab7c080bdad..62a9bf9eb85eb 100644 --- a/packages/react-server/src/ReactFlightReplyServer.js +++ b/packages/react-server/src/ReactFlightReplyServer.js @@ -464,8 +464,6 @@ function initializeModelChunk(chunk: ResolvedModelChunk): void { // We have to go the BLOCKED state until they're resolved. const blockedChunk: BlockedChunk = (chunk: any); blockedChunk.status = BLOCKED; - blockedChunk.value = null; - blockedChunk.reason = null; } else { const resolveListeners = cyclicChunk.value; const initializedChunk: InitializedChunk = (chunk: any);