Skip to content

Commit fe37736

Browse files
committed
Track component logs
1 parent e07235b commit fe37736

2 files changed

Lines changed: 76 additions & 23 deletions

File tree

packages/react-devtools-shared/src/backend/fiber/renderer.js

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ import {
100100
SERVER_CONTEXT_SYMBOL_STRING,
101101
} from '../shared/ReactSymbols';
102102
import {enableStyleXFeatures} from 'react-devtools-feature-flags';
103+
104+
import {componentInfoToComponentLogsMap} from '../shared/DevToolsServerComponentLogs';
105+
103106
import is from 'shared/objectIs';
104107
import hasOwnProperty from 'shared/hasOwnProperty';
105108

@@ -1001,7 +1004,8 @@ export function attach(
10011004
// Note, this only clears logs for Fibers that have instances. If they're filtered
10021005
// and then mount, the logs are there. Ensuring we only clear what you've seen.
10031006
// If we wanted to clear the whole set, we'd replace fiberToComponentLogsMap with a
1004-
// new WeakMap.
1007+
// new WeakMap. It's unclear whether we should clear componentInfoToComponentLogsMap
1008+
// since it's shared by other renderers but presumably it would.
10051009

10061010
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
10071011
for (const devtoolsInstance of idToDevToolsInstanceMap.values()) {
@@ -1012,7 +1016,7 @@ export function attach(
10121016
fiberToComponentLogsMap.delete(fiber.alternate);
10131017
}
10141018
} else {
1015-
// TODO: Handle VirtualInstance.
1019+
componentInfoToComponentLogsMap.delete(devtoolsInstance.data);
10161020
}
10171021
const changed = recordConsoleLogs(devtoolsInstance, undefined);
10181022
if (changed) {
@@ -1025,28 +1029,27 @@ export function attach(
10251029
function clearConsoleLogsHelper(instanceID: number, type: 'error' | 'warn') {
10261030
const devtoolsInstance = idToDevToolsInstanceMap.get(instanceID);
10271031
if (devtoolsInstance !== undefined) {
1032+
let componentLogsEntry;
10281033
if (devtoolsInstance.kind === FIBER_INSTANCE) {
10291034
const fiber = devtoolsInstance.data;
1030-
const componentLogsEntry = fiberToComponentLogsMap.get(fiber);
1031-
if (componentLogsEntry !== undefined) {
1032-
if (type === 'error') {
1033-
componentLogsEntry.errors.clear();
1034-
componentLogsEntry.errorsCount = 0;
1035-
} else {
1036-
componentLogsEntry.warnings.clear();
1037-
componentLogsEntry.warningsCount = 0;
1038-
}
1039-
const changed = recordConsoleLogs(
1040-
devtoolsInstance,
1041-
componentLogsEntry,
1042-
);
1043-
if (changed) {
1044-
flushPendingEvents();
1045-
updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
1046-
}
1047-
}
1035+
componentLogsEntry = fiberToComponentLogsMap.get(fiber);
10481036
} else {
1049-
// TODO: Handle VirtualInstance.
1037+
const componentInfo = devtoolsInstance.data;
1038+
componentLogsEntry = componentInfoToComponentLogsMap.get(componentInfo);
1039+
}
1040+
if (componentLogsEntry !== undefined) {
1041+
if (type === 'error') {
1042+
componentLogsEntry.errors.clear();
1043+
componentLogsEntry.errorsCount = 0;
1044+
} else {
1045+
componentLogsEntry.warnings.clear();
1046+
componentLogsEntry.warningsCount = 0;
1047+
}
1048+
const changed = recordConsoleLogs(devtoolsInstance, componentLogsEntry);
1049+
if (changed) {
1050+
flushPendingEvents();
1051+
updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
1052+
}
10501053
}
10511054
}
10521055
}
@@ -2207,6 +2210,10 @@ export function attach(
22072210
pushOperation(ownerID);
22082211
pushOperation(displayNameStringID);
22092212
pushOperation(keyStringID);
2213+
2214+
const componentLogsEntry =
2215+
componentInfoToComponentLogsMap.get(componentInfo);
2216+
recordConsoleLogs(instance, componentLogsEntry);
22102217
}
22112218

22122219
function recordUnmount(fiberInstance: FiberInstance): void {
@@ -2886,6 +2893,14 @@ export function attach(
28862893
) {
28872894
recordResetChildren(virtualInstance);
28882895
}
2896+
// Update the errors/warnings count. If this Instance has switched to a different
2897+
// ReactComponentInfo instance, such as when refreshing Server Components, then
2898+
// we replace all the previous logs with the ones associated with the new ones rather
2899+
// than merging. Because deduping is expected to happen at the request level.
2900+
const componentLogsEntry = componentInfoToComponentLogsMap.get(
2901+
virtualInstance.data,
2902+
);
2903+
recordConsoleLogs(virtualInstance, componentLogsEntry);
28892904
// Must be called after all children have been appended.
28902905
recordVirtualProfilingDurations(virtualInstance);
28912906
} finally {
@@ -4335,6 +4350,9 @@ export function attach(
43354350
stylex: null,
43364351
};
43374352

4353+
const componentLogsEntry =
4354+
componentInfoToComponentLogsMap.get(componentInfo);
4355+
43384356
return {
43394357
id: virtualInstance.id,
43404358

@@ -4368,8 +4386,14 @@ export function attach(
43684386
hooks: null,
43694387
props: props,
43704388
state: null,
4371-
errors: [], // TODO: Handle errors on Virtual Instances.
4372-
warnings: [], // TODO: Handle warnings on Virtual Instances.
4389+
errors:
4390+
componentLogsEntry === undefined
4391+
? []
4392+
: Array.from(componentLogsEntry.errors.entries()),
4393+
warnings:
4394+
componentLogsEntry === undefined
4395+
? []
4396+
: Array.from(componentLogsEntry.warnings.entries()),
43734397
// List of owners
43744398
owners,
43754399

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
// This keeps track of Server Component logs which may come from.
11+
// This is in a shared module because Server Component logs don't come from a specific renderer
12+
// but can become associated with a Virtual Instance of any renderer.
13+
14+
import type {ReactComponentInfo} from 'shared/ReactTypes';
15+
16+
type ComponentLogs = {
17+
errors: Map<string, number>,
18+
errorsCount: number,
19+
warnings: Map<string, number>,
20+
warningsCount: number,
21+
};
22+
23+
// This keeps it around as long as the ComponentInfo is alive which
24+
// lets the Fiber get reparented/remounted and still observe the previous errors/warnings.
25+
// Unless we explicitly clear the logs from a Fiber.
26+
export const componentInfoToComponentLogsMap: WeakMap<
27+
ReactComponentInfo,
28+
ComponentLogs,
29+
> = new WeakMap();

0 commit comments

Comments
 (0)