Skip to content

Commit 8aafbcf

Browse files
authored
[Flight] Fully support serializing Map/Set in console logs (facebook#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.
1 parent ba95cf4 commit 8aafbcf

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -2628,7 +2628,7 @@ describe('ReactFlight', () => {
26282628
return 'hello';
26292629
}
26302630
function ServerComponent() {
2631-
console.log('hi', {prop: 123, fn: foo});
2631+
console.log('hi', {prop: 123, fn: foo, map: new Map([['foo', foo]])});
26322632
throw new Error('err');
26332633
}
26342634

@@ -2670,6 +2670,13 @@ describe('ReactFlight', () => {
26702670
expect(typeof loggedFn).toBe('function');
26712671
expect(loggedFn).not.toBe(foo);
26722672
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());
26732680
});
26742681

26752682
it('uses the server component debug info as the element owner in DEV', async () => {

packages/react-server/src/ReactFlightServer.js

+24-2
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,28 @@ function serializeSet(request: Request, set: Set<ReactClientValue>): string {
20212021
return '$W' + id.toString(16);
20222022
}
20232023

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+
20242046
function serializeIterator(
20252047
request: Request,
20262048
iterator: Iterator<ReactClientValue>,
@@ -3220,10 +3242,10 @@ function renderConsoleValue(
32203242
}
32213243

32223244
if (value instanceof Map) {
3223-
return serializeMap(request, value);
3245+
return serializeConsoleMap(request, counter, value);
32243246
}
32253247
if (value instanceof Set) {
3226-
return serializeSet(request, value);
3248+
return serializeConsoleSet(request, counter, value);
32273249
}
32283250
// TODO: FormData is not available in old Node. Remove the typeof later.
32293251
if (typeof FormData === 'function' && value instanceof FormData) {

0 commit comments

Comments
 (0)