diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index a31d4a39554c3..3129437fa4332 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -641,7 +641,12 @@ function createElement( } // TODO: We should be freezing the element but currently, we might write into // _debugInfo later. We could move it into _store which remains mutable. - Object.freeze(element.props); + if (initializingChunkBlockedModel !== null) { + const freeze = Object.freeze.bind(Object, element.props); + initializingChunk.then(freeze, freeze); + } else { + Object.freeze(element.props); + } } return element; } 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 55ccb44fb041c..d0630287dbf8b 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -198,6 +198,55 @@ describe('ReactFlightDOMBrowser', () => { }); }); + it('should resolve client components (with async chunks) when referenced in props', async () => { + let resolveClientComponentChunk; + + const ClientOuter = clientExports(function ClientOuter({ + Component, + children, + }) { + return {children}; + }); + + const ClientInner = clientExports( + function ClientInner({children}) { + return {children}; + }, + '42', + '/test.js', + new Promise(resolve => (resolveClientComponentChunk = resolve)), + ); + + function Server() { + return Hello, World!; + } + + 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('Hello, World!'); + }); + it('should progressively reveal server components', async () => { let reportedErrors = []; diff --git a/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js b/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js index cf21030834438..4527118c1de8b 100644 --- a/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js +++ b/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js @@ -69,10 +69,15 @@ exports.clientExports = function clientExports( moduleExports, chunkId, chunkFilename, + blockOnChunk, ) { const chunks = []; if (chunkId) { chunks.push(chunkId, chunkFilename); + + if (blockOnChunk) { + webpackChunkMap[chunkId] = blockOnChunk; + } } const idx = '' + webpackModuleIdx++; webpackClientModules[idx] = moduleExports;