Skip to content

Commit 9c47351

Browse files
committed
[DevTools] Fix broken commit tree builder for initial operations
1 parent 3267860 commit 9c47351

File tree

6 files changed

+44
-27
lines changed

6 files changed

+44
-27
lines changed

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

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ export function attach(
11381138
// if any passive effects called console.warn / console.error.
11391139
let needsToFlushComponentLogs = false;
11401140
1141-
function bruteForceFlushErrorsAndWarnings() {
1141+
function bruteForceFlushErrorsAndWarnings(root: FiberInstance) {
11421142
// Refresh error/warning count for all mounted unfiltered Fibers.
11431143
let hasChanges = false;
11441144
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
@@ -1156,7 +1156,7 @@ export function attach(
11561156
}
11571157
}
11581158
if (hasChanges) {
1159-
flushPendingEvents();
1159+
flushPendingEvents(root);
11601160
}
11611161
}
11621162
@@ -1183,7 +1183,7 @@ export function attach(
11831183
updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
11841184
}
11851185
}
1186-
flushPendingEvents();
1186+
flushPendingEvents(null);
11871187
}
11881188
11891189
function clearConsoleLogsHelper(instanceID: number, type: 'error' | 'warn') {
@@ -1211,7 +1211,7 @@ export function attach(
12111211
}
12121212
const changed = recordConsoleLogs(devtoolsInstance, componentLogsEntry);
12131213
if (changed) {
1214-
flushPendingEvents();
1214+
flushPendingEvents(null);
12151215
updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
12161216
}
12171217
}
@@ -1533,6 +1533,8 @@ export function attach(
15331533
if (isProfiling) {
15341534
// Re-mounting a tree while profiling is in progress might break a lot of assumptions.
15351535
// If necessary, we could support this- but it doesn't seem like a necessary use case.
1536+
// Supporting change of filters while profiling would require a refactor
1537+
// to after each root instead of at the end.
15361538
throw Error('Cannot modify filter preferences while profiling');
15371539
}
15381540
@@ -1647,7 +1649,8 @@ export function attach(
16471649
focusedActivityFilter.activityID = focusedActivityID;
16481650
}
16491651
1650-
flushPendingEvents();
1652+
// We're not profiling so it's safe to flush without a specific root.
1653+
flushPendingEvents(null);
16511654
16521655
needsToFlushComponentLogs = false;
16531656
}
@@ -2203,7 +2206,12 @@ export function attach(
22032206
}
22042207
}
22052208
2206-
function flushPendingEvents(): void {
2209+
/**
2210+
* Allowed to flush pending events without a specific root when:
2211+
* - pending operations don't record tree mutations e.g. TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS
2212+
* - not profiling (the commit tree builder requires the root of the mutations)
2213+
*/
2214+
function flushPendingEvents(root: FiberInstance | null): void {
22072215
if (shouldBailoutWithPendingOperations()) {
22082216
// If we aren't profiling, we can just bail out here.
22092217
// No use sending an empty update over the bridge.
@@ -2222,7 +2230,7 @@ export function attach(
22222230
22232231
const operations = new Array<number>(
22242232
// Identify which renderer this update is coming from.
2225-
1 + // [rendererID]
2233+
2 + // [rendererID, rootFiberID]
22262234
// How big is the string table?
22272235
1 + // [stringTableLength]
22282236
// Then goes the actual string table.
@@ -2245,6 +2253,11 @@ export function attach(
22452253
// Which in turn enables fiber props, states, and hooks to be inspected.
22462254
let i = 0;
22472255
operations[i++] = rendererID;
2256+
if (root === null) {
2257+
operations[i++] = -1;
2258+
} else {
2259+
operations[i++] = root.id;
2260+
}
22482261
22492262
// Now fill in the string table.
22502263
// [stringTableLength, str1Length, ...str1, str2Length, ...str2, ...]
@@ -5740,11 +5753,11 @@ export function attach(
57405753
57415754
mountFiberRecursively(root.current, false);
57425755
5756+
flushPendingEvents(currentRoot);
5757+
57435758
currentRoot = (null: any);
57445759
});
57455760
5746-
flushPendingEvents();
5747-
57485761
needsToFlushComponentLogs = false;
57495762
}
57505763
}
@@ -5754,7 +5767,7 @@ export function attach(
57545767
// safe to stop calling it from Fiber.
57555768
}
57565769
5757-
function handlePostCommitFiberRoot(root: any) {
5770+
function handlePostCommitFiberRoot(root: FiberRoot) {
57585771
if (isProfiling && rootSupportsProfiling(root)) {
57595772
if (currentCommitProfilingMetadata !== null) {
57605773
const {effectDuration, passiveEffectDuration} =
@@ -5768,12 +5781,18 @@ export function attach(
57685781
}
57695782
57705783
if (needsToFlushComponentLogs) {
5784+
const rootInstance = rootToFiberInstanceMap.get(root);
5785+
if (rootInstance === undefined) {
5786+
throw new Error(
5787+
'Should have a root instance for a committed root. This is a bug in React DevTools.',
5788+
);
5789+
}
57715790
// We received new logs after commit. I.e. in a passive effect. We need to
57725791
// traverse the tree to find the affected ones. If we just moved the whole
57735792
// tree traversal from handleCommitFiberRoot to handlePostCommitFiberRoot
57745793
// this wouldn't be needed. For now we just brute force check all instances.
57755794
// This is not that common of a case.
5776-
bruteForceFlushErrorsAndWarnings();
5795+
bruteForceFlushErrorsAndWarnings(rootInstance);
57775796
}
57785797
}
57795798
@@ -5870,7 +5889,7 @@ export function attach(
58705889
}
58715890
58725891
// We're done here.
5873-
flushPendingEvents();
5892+
flushPendingEvents(currentRoot);
58745893
58755894
needsToFlushComponentLogs = false;
58765895

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ export function attach(
525525

526526
const operations = new Array<number>(
527527
// Identify which renderer this update is coming from.
528-
1 + // [rendererID]
528+
2 + // [rendererID, rootFiberID]
529529
// How big is the string table?
530530
1 + // [stringTableLength]
531531
// Then goes the actual string table.
@@ -544,6 +544,7 @@ export function attach(
544544
// Which in turn enables fiber properations, states, and hooks to be inspected.
545545
let i = 0;
546546
operations[i++] = rendererID;
547+
operations[i++] = rootID;
547548

548549
// Now fill in the string table.
549550
// [stringTableLength, str1Length, ...str1, str2Length, ...str2, ...]

packages/react-devtools-shared/src/bridge.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ export const BRIDGE_PROTOCOL: Array<BridgeProtocol> = [
6767
minNpmVersion: '4.22.0',
6868
maxNpmVersion: null,
6969
},
70-
// Version 3 no longer sends a rootFiberID at the start
71-
{
72-
version: 3,
73-
minNpmVersion: '7.1.0',
74-
maxNpmVersion: null,
75-
},
7670
];
7771

7872
export const currentBridgeProtocol: BridgeProtocol =

packages/react-devtools-shared/src/devtools/store.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,9 +1350,8 @@ export default class Store extends EventEmitter<{
13501350
let haveErrorsOrWarningsChanged = false;
13511351
let hasSuspenseTreeChanged = false;
13521352

1353-
// The first value is always rendererID
1354-
let i = 0;
1355-
const rendererID = operations[i++];
1353+
// The first two values are always rendererID and rootID
1354+
const rendererID = operations[0];
13561355

13571356
const addedElementIDs: Array<number> = [];
13581357
// This is a mapping of removed ID -> parent ID:
@@ -1362,6 +1361,8 @@ export default class Store extends EventEmitter<{
13621361
new Map();
13631362
let nextActivitySliceID: Element['id'] | null = null;
13641363

1364+
let i = 2;
1365+
13651366
// Reassemble the string table.
13661367
const stringTable: Array<string | null> = [
13671368
null, // ID = 0 corresponds to the null string.

packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ function updateTree(
171171
return clonedNode;
172172
};
173173

174-
let i = 1;
174+
let i = 2;
175175
let id: number = ((null: any): number);
176176

177177
// Reassemble the string table.

packages/react-devtools-shared/src/utils.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,13 @@ export function utfEncodeString(string: string): Array<number> {
221221
}
222222

223223
export function printOperationsArray(operations: Array<number>) {
224-
// The first value is always rendererID
225-
let i = 0;
226-
const rendererID = operations[i++];
224+
// The first two values are always rendererID and rootID
225+
const rendererID = operations[0];
226+
const rootID = operations[1];
227+
228+
const logs = [`operations for renderer:${rendererID} and root:${rootID}`];
227229

228-
const logs = [`operations for renderer:${rendererID}`];
230+
let i = 2;
229231

230232
// Reassemble the string table.
231233
const stringTable: Array<null | string> = [

0 commit comments

Comments
 (0)