Skip to content

Commit 4262127

Browse files
committed
[Flight] Do not redefine debugInfo on JSX elements
1 parent 408b38e commit 4262127

File tree

2 files changed

+34
-18
lines changed

2 files changed

+34
-18
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -524,16 +524,24 @@ function moveDebugInfoFromChunkToInnerValue<T>(
524524
debugInfo,
525525
);
526526
} else {
527-
Object.defineProperty((resolvedValue: any), '_debugInfo', {
528-
configurable: false,
529-
enumerable: false,
530-
writable: true,
531-
value: debugInfo,
532-
});
527+
setDebugInfo(resolvedValue, debugInfo);
533528
}
534529
}
535530
}
536531

532+
function setDebugInfo(value: any, debugInfo: Array<ReactDebugInfoEntry>) {
533+
// Only set if property is writable. If the value is a JSX element, it will be frozen.
534+
const descriptor = Object.getOwnPropertyDescriptor(value, '_debugInfo');
535+
if (!descriptor || descriptor.writable) {
536+
Object.defineProperty(value, '_debugInfo', {
537+
configurable: false,
538+
enumerable: false,
539+
writable: true,
540+
value: debugInfo,
541+
});
542+
}
543+
}
544+
537545
function wakeChunk<T>(
538546
listeners: Array<InitializationReference | (T => mixed)>,
539547
value: T,
@@ -1219,12 +1227,7 @@ function initializeElement(
12191227
// $FlowFixMe[method-unbinding]
12201228
element._debugInfo.unshift.apply(element._debugInfo, debugInfo);
12211229
} else {
1222-
Object.defineProperty(element, '_debugInfo', {
1223-
configurable: false,
1224-
enumerable: false,
1225-
writable: true,
1226-
value: debugInfo,
1227-
});
1230+
setDebugInfo(element, debugInfo);
12281231
}
12291232
}
12301233
}
@@ -2797,12 +2800,7 @@ function addAsyncInfo(chunk: SomeChunk<any>, asyncInfo: ReactAsyncInfo): void {
27972800
// $FlowFixMe[method-unbinding]
27982801
value._debugInfo.push(asyncInfo);
27992802
} else {
2800-
Object.defineProperty((value: any), '_debugInfo', {
2801-
configurable: false,
2802-
enumerable: false,
2803-
writable: true,
2804-
value: [asyncInfo],
2805-
});
2803+
setDebugInfo(value, [asyncInfo]);
28062804
}
28072805
} else {
28082806
// $FlowFixMe[method-unbinding]

packages/react-client/src/__tests__/ReactFlight-test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3884,4 +3884,22 @@ describe('ReactFlight', () => {
38843884
</main>,
38853885
);
38863886
});
3887+
3888+
it('does not crash when exporting a JSX element as a client reference', async () => {
3889+
const ClientReference = clientReference(React.createElement('div'));
3890+
3891+
function App() {
3892+
return ClientReference;
3893+
}
3894+
3895+
const transport = ReactNoopFlightServer.render({
3896+
root: ReactServer.createElement(App),
3897+
});
3898+
3899+
await act(async () => {
3900+
const {root} = await ReactNoopFlightClient.read(transport);
3901+
ReactNoop.render(root);
3902+
expect(getDebugInfo(root)).toBeNull();
3903+
});
3904+
});
38873905
});

0 commit comments

Comments
 (0)