Skip to content

Commit af3a55e

Browse files
Lazily freeze in case anything in the currently initializing chunk is blocked (#29139)
Fixed #29129. --------- Co-authored-by: Hendrik Liebau <[email protected]>
1 parent 477a3d1 commit af3a55e

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,12 @@ function createElement(
641641
}
642642
// TODO: We should be freezing the element but currently, we might write into
643643
// _debugInfo later. We could move it into _store which remains mutable.
644-
Object.freeze(element.props);
644+
if (initializingChunkBlockedModel !== null) {
645+
const freeze = Object.freeze.bind(Object, element.props);
646+
initializingChunk.then(freeze, freeze);
647+
} else {
648+
Object.freeze(element.props);
649+
}
645650
}
646651
return element;
647652
}

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,55 @@ describe('ReactFlightDOMBrowser', () => {
198198
});
199199
});
200200

201+
it('should resolve client components (with async chunks) when referenced in props', async () => {
202+
let resolveClientComponentChunk;
203+
204+
const ClientOuter = clientExports(function ClientOuter({
205+
Component,
206+
children,
207+
}) {
208+
return <Component>{children}</Component>;
209+
});
210+
211+
const ClientInner = clientExports(
212+
function ClientInner({children}) {
213+
return <span>{children}</span>;
214+
},
215+
'42',
216+
'/test.js',
217+
new Promise(resolve => (resolveClientComponentChunk = resolve)),
218+
);
219+
220+
function Server() {
221+
return <ClientOuter Component={ClientInner}>Hello, World!</ClientOuter>;
222+
}
223+
224+
const stream = ReactServerDOMServer.renderToReadableStream(
225+
<Server />,
226+
webpackMap,
227+
);
228+
229+
function ClientRoot({response}) {
230+
return use(response);
231+
}
232+
233+
const response = ReactServerDOMClient.createFromReadableStream(stream);
234+
const container = document.createElement('div');
235+
const root = ReactDOMClient.createRoot(container);
236+
237+
await act(() => {
238+
root.render(<ClientRoot response={response} />);
239+
});
240+
241+
expect(container.innerHTML).toBe('');
242+
243+
await act(() => {
244+
resolveClientComponentChunk();
245+
});
246+
247+
expect(container.innerHTML).toBe('<span>Hello, World!</span>');
248+
});
249+
201250
it('should progressively reveal server components', async () => {
202251
let reportedErrors = [];
203252

packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,15 @@ exports.clientExports = function clientExports(
6969
moduleExports,
7070
chunkId,
7171
chunkFilename,
72+
blockOnChunk,
7273
) {
7374
const chunks = [];
7475
if (chunkId) {
7576
chunks.push(chunkId, chunkFilename);
77+
78+
if (blockOnChunk) {
79+
webpackChunkMap[chunkId] = blockOnChunk;
80+
}
7681
}
7782
const idx = '' + webpackModuleIdx++;
7883
webpackClientModules[idx] = moduleExports;

0 commit comments

Comments
 (0)