@samitouri / QOS-React / commits / 8aafbcf115

[Flight] Fully support serializing Map/Set in console logs (#30295)

Currently we serialize Map/Set through our regular flow and not the console serialization. The console one is more forgiving than the regular one.

Sebastian Markbåge committed Jul 9, 2024 at 14:22 UTC 8aafbcf115e67df899ddbb180ef025c7c260a3fe
2 files changed +32 -3
packages/react-client/src/__tests__/ReactFlight-test.js
+8 -1
@@ -2628,7 +2628,7 @@ describe('ReactFlight', () => {
2628 return 'hello';
2629 }
2630 function ServerComponent() {
2631 - console.log('hi', {prop: 123, fn: foo});
2631 + console.log('hi', {prop: 123, fn: foo, map: new Map([['foo', foo]])});
2632 throw new Error('err');
2633 }
2634
@@ -2670,6 +2670,13 @@ describe('ReactFlight', () => {
2670 expect(typeof loggedFn).toBe('function');
2671 expect(loggedFn).not.toBe(foo);
2672 expect(loggedFn.toString()).toBe(foo.toString());
2673 +
2674 + const loggedMap = mockConsoleLog.mock.calls[0][1].map;
2675 + expect(loggedMap instanceof Map).toBe(true);
2676 + const loggedFn2 = loggedMap.get('foo');
2677 + expect(typeof loggedFn2).toBe('function');
2678 + expect(loggedFn2).not.toBe(foo);
2679 + expect(loggedFn2.toString()).toBe(foo.toString());
2680 });
2681
2682 it('uses the server component debug info as the element owner in DEV', async () => {
packages/react-server/src/ReactFlightServer.js
+24 -2
@@ -2021,6 +2021,28 @@ function serializeSet(request: Request, set: Set<ReactClientValue>): string {
2021 return '$W' + id.toString(16);
2022 }
2023
2024 +function serializeConsoleMap(
2025 + request: Request,
2026 + counter: {objectCount: number},
2027 + map: Map<ReactClientValue, ReactClientValue>,
2028 +): string {
2029 + // Like serializeMap but for renderConsoleValue.
2030 + const entries = Array.from(map);
2031 + const id = outlineConsoleValue(request, counter, entries);
2032 + return '$Q' + id.toString(16);
2033 +}
2034 +
2035 +function serializeConsoleSet(
2036 + request: Request,
2037 + counter: {objectCount: number},
2038 + set: Set<ReactClientValue>,
2039 +): string {
2040 + // Like serializeMap but for renderConsoleValue.
2041 + const entries = Array.from(set);
2042 + const id = outlineConsoleValue(request, counter, entries);
2043 + return '$W' + id.toString(16);
2044 +}
2045 +
2046 function serializeIterator(
2047 request: Request,
2048 iterator: Iterator<ReactClientValue>,
@@ -3220,10 +3242,10 @@ function renderConsoleValue(
3242 }
3243
3244 if (value instanceof Map) {
3223 - return serializeMap(request, value);
3245 + return serializeConsoleMap(request, counter, value);
3246 }
3247 if (value instanceof Set) {
3226 - return serializeSet(request, value);
3248 + return serializeConsoleSet(request, counter, value);
3249 }
3250 // TODO: FormData is not available in old Node. Remove the typeof later.
3251 if (typeof FormData === 'function' && value instanceof FormData) {