[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) {