@samitouri / QOS-React-1 / commits / af3a55e67f

Lazily freeze in case anything in the currently initializing chunk is blocked (#29139)

Fixed #29129. --------- Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>

Sebastian Markbåge committed May 17, 2024 at 13:58 UTC af3a55e67f0fc9c981b5fe63162b2770ca9548b1
3 files changed +60 -1
packages/react-client/src/ReactFlightClient.js
+6 -1
@@ -641,7 +641,12 @@ function createElement(
641 }
642 // TODO: We should be freezing the element but currently, we might write into
643 // _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 + }
650 }
651 return element;
652 }
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
+49
@@ -198,6 +198,55 @@ describe('ReactFlightDOMBrowser', () => {
198 });
199 });
200
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 +
250 it('should progressively reveal server components', async () => {
251 let reportedErrors = [];
252
packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js
+5
@@ -69,10 +69,15 @@ exports.clientExports = function clientExports(
69 moduleExports,
70 chunkId,
71 chunkFilename,
72 + blockOnChunk,
73 ) {
74 const chunks = [];
75 if (chunkId) {
76 chunks.push(chunkId, chunkFilename);
77 +
78 + if (blockOnChunk) {
79 + webpackChunkMap[chunkId] = blockOnChunk;
80 + }
81 }
82 const idx = '' + webpackModuleIdx++;
83 webpackClientModules[idx] = moduleExports;