@samitouri / QOS-React-2 / commits / 0ba4d7b0d8

DevTools: Inline references to fiber flags (#26542)

We shouldn't be referencing internal fields like fiber's `flag` directly of DevTools. It's an implementation detail. However, over the years a few of these have snuck in. Because of how DevTools is currently shipped, where it's expected to be backwards compatible with older versions of React, this prevents us from refactoring those fields inside the reconciler. The plan we have to address this is to fix how DevTools is shipped: DevTools will be released in lockstep with each version of React. Until then, though, I need a temporary solution because it's blocking a feature I'm working on. So in meantime, I'm going to have to fork the DevTool's code based on the React version, like we already do with the fiber TypeOfWork enum. As a first step, I've inlined all the references to fiber flags into the specific call sites where they are used. Eventually we'll import these functions from the reconciler so they stay in sync, rather than maintaining duplicate copies of the logic.

Andrew Clark committed Apr 4, 2023 at 11:05 UTC 0ba4d7b0d80d942dc8f074f7ce0536e6b2559fbf
2 files changed +19 -30
packages/react-devtools-shared/src/backend/ReactFiberFlags.js deleted
-17
@@ -1,17 +0,0 @@
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 list of flags must be synced with the following file:
11 -// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberFlags.js
12 -
13 -export const NoFlags = /* */ 0b000000000000000000000000000;
14 -export const PerformedWork = /* */ 0b000000000000000000000000001;
15 -export const Placement = /* */ 0b000000000000000000000000010;
16 -export const DidCapture = /* */ 0b000000000000000000010000000;
17 -export const Hydrating = /* */ 0b000000000000001000000000000;
packages/react-devtools-shared/src/backend/renderer.js
+19 -13
@@ -88,13 +88,6 @@ import {
88 MEMO_SYMBOL_STRING,
89 SERVER_CONTEXT_SYMBOL_STRING,
90 } from './ReactSymbols';
91 -import {
92 - DidCapture,
93 - NoFlags,
94 - PerformedWork,
95 - Placement,
96 - Hydrating,
97 -} from './ReactFiberFlags';
91 import {format} from './utils';
92 import {
93 enableProfilerChangedHookIndices,
@@ -1555,7 +1548,10 @@ export function attach(
1548 case ForwardRef:
1549 // For types that execute user code, we check PerformedWork effect.
1550 // We don't reflect bailouts (either referential or sCU) in DevTools.
1558 - // eslint-disable-next-line no-bitwise
1551 + // TODO: This flag is a leaked implementation detail. Once we start
1552 + // releasing DevTools in lockstep with React, we should import a
1553 + // function from the reconciler instead.
1554 + const PerformedWork = 0b000000000000000000000000001;
1555 return (getFiberFlags(nextFiber) & PerformedWork) === PerformedWork;
1556 // Note: ContextConsumer only gets PerformedWork effect in 16.3.3+
1557 // so it won't get highlighted with React 16.3.0 to 16.3.2.
@@ -2843,7 +2839,12 @@ export function attach(
2839 let nextNode: Fiber = node;
2840 do {
2841 node = nextNode;
2846 - if ((node.flags & (Placement | Hydrating)) !== NoFlags) {
2842 + // TODO: This function, and these flags, are a leaked implementation
2843 + // detail. Once we start releasing DevTools in lockstep with React, we
2844 + // should import a function from the reconciler instead.
2845 + const Placement = 0b000000000000000000000000010;
2846 + const Hydrating = 0b000000000000001000000000000;
2847 + if ((node.flags & (Placement | Hydrating)) !== 0) {
2848 // This is an insertion or in-progress hydration. The nearest possible
2849 // mounted fiber is the parent but we need to continue to figure out
2850 // if that one is still mounted.
@@ -3300,16 +3301,21 @@ export function attach(
3301 const errors = fiberIDToErrorsMap.get(id) || new Map();
3302 const warnings = fiberIDToWarningsMap.get(id) || new Map();
3303
3303 - const isErrored =
3304 - (fiber.flags & DidCapture) !== NoFlags ||
3305 - forceErrorForFiberIDs.get(id) === true;
3306 -
3304 + let isErrored = false;
3305 let targetErrorBoundaryID;
3306 if (isErrorBoundary(fiber)) {
3307 // if the current inspected element is an error boundary,
3308 // either that we want to use it to toggle off error state
3309 // or that we allow to force error state on it if it's within another
3310 // error boundary
3311 + //
3312 + // TODO: This flag is a leaked implementation detail. Once we start
3313 + // releasing DevTools in lockstep with React, we should import a function
3314 + // from the reconciler instead.
3315 + const DidCapture = 0b000000000000000000010000000;
3316 + isErrored =
3317 + (fiber.flags & DidCapture) !== 0 ||
3318 + forceErrorForFiberIDs.get(id) === true;
3319 targetErrorBoundaryID = isErrored ? id : getNearestErrorBoundaryID(fiber);
3320 } else {
3321 targetErrorBoundaryID = getNearestErrorBoundaryID(fiber);