Skip to content

Commit 8bd81ea

Browse files
committed
Filtered Fiber Instances
1 parent e0a07e9 commit 8bd81ea

File tree

1 file changed

+112
-27
lines changed
  • packages/react-devtools-shared/src/backend/fiber

1 file changed

+112
-27
lines changed

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

Lines changed: 112 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ import {formatOwnerStack} from '../shared/DevToolsOwnerStack';
146146
// Kinds
147147
const FIBER_INSTANCE = 0;
148148
const VIRTUAL_INSTANCE = 1;
149+
const FILTERED_FIBER_INSTANCE = 2;
149150

150151
// Flags
151152
const FORCE_SUSPENSE_FALLBACK = /* */ 0b001;
@@ -157,9 +158,9 @@ const FORCE_ERROR_RESET = /* */ 0b100;
157158
type FiberInstance = {
158159
kind: 0,
159160
id: number,
160-
parent: null | DevToolsInstance, // filtered parent, including virtual
161-
firstChild: null | DevToolsInstance, // filtered first child, including virtual
162-
nextSibling: null | DevToolsInstance, // filtered next sibling, including virtual
161+
parent: null | DevToolsInstance,
162+
firstChild: null | DevToolsInstance,
163+
nextSibling: null | DevToolsInstance,
163164
flags: number, // Force Error/Suspense
164165
source: null | string | Error | Source, // source location of this component function, or owned child stack
165166
errors: null | Map<string, number>, // error messages and count
@@ -184,6 +185,39 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
184185
};
185186
}
186187

188+
type FilteredFiberInstance = {
189+
kind: 2,
190+
// We exclude id from the type to get errors if we try to access it.
191+
// However it is still in the object to preserve hidden class.
192+
// id: number,
193+
parent: null | DevToolsInstance,
194+
firstChild: null | DevToolsInstance,
195+
nextSibling: null | DevToolsInstance,
196+
flags: number, // Force Error/Suspense
197+
source: null | string | Error | Source, // always null here.
198+
errors: null, // error messages and count
199+
warnings: null, // warning messages and count
200+
treeBaseDuration: number, // the profiled time of the last render of this subtree
201+
data: Fiber, // one of a Fiber pair
202+
};
203+
204+
// This is used to represent a filtered Fiber but still lets us find its host instance.
205+
function createFilteredFiberInstance(fiber: Fiber): FilteredFiberInstance {
206+
return ({
207+
kind: FILTERED_FIBER_INSTANCE,
208+
id: 0,
209+
parent: null,
210+
firstChild: null,
211+
nextSibling: null,
212+
flags: 0,
213+
componentStack: null,
214+
errors: null,
215+
warnings: null,
216+
treeBaseDuration: 0,
217+
data: fiber,
218+
}: any);
219+
}
220+
187221
// This type represents a stateful instance of a Server Component or a Component
188222
// that gets optimized away - e.g. call-through without creating a Fiber.
189223
// It's basically a virtual Fiber. This is not a semantic concept in React.
@@ -192,9 +226,9 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
192226
type VirtualInstance = {
193227
kind: 1,
194228
id: number,
195-
parent: null | DevToolsInstance, // filtered parent, including virtual
196-
firstChild: null | DevToolsInstance, // filtered first child, including virtual
197-
nextSibling: null | DevToolsInstance, // filtered next sibling, including virtual
229+
parent: null | DevToolsInstance,
230+
firstChild: null | DevToolsInstance,
231+
nextSibling: null | DevToolsInstance,
198232
flags: number,
199233
source: null | string | Error | Source, // source location of this server component, or owned child stack
200234
// Errors and Warnings happen per ReactComponentInfo which can appear in
@@ -226,7 +260,7 @@ function createVirtualInstance(
226260
};
227261
}
228262

229-
type DevToolsInstance = FiberInstance | VirtualInstance;
263+
type DevToolsInstance = FiberInstance | VirtualInstance | FilteredFiberInstance;
230264

231265
type getDisplayNameForFiberType = (fiber: Fiber) => string | null;
232266
type getTypeSymbolType = (type: any) => symbol | number;
@@ -736,7 +770,8 @@ const fiberToFiberInstanceMap: Map<Fiber, FiberInstance> = new Map();
736770
// Map of id to one (arbitrary) Fiber in a pair.
737771
// This Map is used to e.g. get the display name for a Fiber or schedule an update,
738772
// operations that should be the same whether the current and work-in-progress Fiber is used.
739-
const idToDevToolsInstanceMap: Map<number, DevToolsInstance> = new Map();
773+
const idToDevToolsInstanceMap: Map<number, FiberInstance | VirtualInstance> =
774+
new Map();
740775

741776
// Map of resource DOM nodes to all the Fibers that depend on it.
742777
const hostResourceToFiberMap: Map<HostInstance, Set<Fiber>> = new Map();
@@ -1083,13 +1118,22 @@ export function attach(
10831118
function debugTree(instance: DevToolsInstance, indent: number = 0) {
10841119
if (__DEBUG__) {
10851120
const name =
1086-
(instance.kind === FIBER_INSTANCE
1121+
(instance.kind !== VIRTUAL_INSTANCE
10871122
? getDisplayNameForFiber(instance.data)
10881123
: instance.data.name) || '';
10891124
console.log(
1090-
' '.repeat(indent) + '- ' + instance.id + ' (' + name + ')',
1125+
' '.repeat(indent) +
1126+
'- ' +
1127+
(instance.kind === FILTERED_FIBER_INSTANCE ? 0 : instance.id) +
1128+
' (' +
1129+
name +
1130+
')',
10911131
'parent',
1092-
instance.parent === null ? ' ' : instance.parent.id,
1132+
instance.parent === null
1133+
? ' '
1134+
: instance.parent.kind === FILTERED_FIBER_INSTANCE
1135+
? 0
1136+
: instance.parent.id,
10931137
'next',
10941138
instance.nextSibling === null ? ' ' : instance.nextSibling.id,
10951139
);
@@ -2227,7 +2271,12 @@ export function attach(
22272271
ownerInstance.source = fiber._debugStack;
22282272
}
22292273
const ownerID = ownerInstance === null ? 0 : ownerInstance.id;
2230-
const parentID = parentInstance ? parentInstance.id : 0;
2274+
const parentID = parentInstance
2275+
? parentInstance.kind === FILTERED_FIBER_INSTANCE
2276+
? // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
2277+
((parentInstance.parent: any): VirtualInstance).id
2278+
: parentInstance.id
2279+
: 0;
22312280

22322281
const displayNameStringID = getStringID(displayName);
22332282

@@ -2311,7 +2360,12 @@ export function attach(
23112360
ownerInstance.source = componentInfo.debugStack;
23122361
}
23132362
const ownerID = ownerInstance === null ? 0 : ownerInstance.id;
2314-
const parentID = parentInstance ? parentInstance.id : 0;
2363+
const parentID = parentInstance
2364+
? parentInstance.kind === FILTERED_FIBER_INSTANCE
2365+
? // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
2366+
((parentInstance.parent: any): VirtualInstance).id
2367+
: parentInstance.id
2368+
: 0;
23152369

23162370
const displayNameStringID = getStringID(displayName);
23172371

@@ -2636,6 +2690,14 @@ export function attach(
26362690
if (shouldIncludeInTree) {
26372691
newInstance = recordMount(fiber, reconcilingParent);
26382692
insertChild(newInstance);
2693+
} else if (
2694+
reconcilingParent !== null &&
2695+
reconcilingParent.kind === VIRTUAL_INSTANCE
2696+
) {
2697+
// If the parent is a Virtual Instance and we filtered this Fiber we include a
2698+
// hidden node.
2699+
newInstance = createFilteredFiberInstance(fiber);
2700+
insertChild(newInstance);
26392701
}
26402702

26412703
// If we have the tree selection from previous reload, try to match this Fiber.
@@ -2648,7 +2710,7 @@ export function attach(
26482710
const stashedParent = reconcilingParent;
26492711
const stashedPrevious = previouslyReconciledSibling;
26502712
const stashedRemaining = remainingReconcilingChildren;
2651-
if (shouldIncludeInTree) {
2713+
if (newInstance !== null) {
26522714
// Push a new DevTools instance parent while reconciling this subtree.
26532715
reconcilingParent = newInstance;
26542716
previouslyReconciledSibling = null;
@@ -2719,7 +2781,7 @@ export function attach(
27192781
}
27202782
}
27212783
} finally {
2722-
if (shouldIncludeInTree) {
2784+
if (newInstance !== null) {
27232785
reconcilingParent = stashedParent;
27242786
previouslyReconciledSibling = stashedPrevious;
27252787
remainingReconcilingChildren = stashedRemaining;
@@ -2759,8 +2821,10 @@ export function attach(
27592821
}
27602822
if (instance.kind === FIBER_INSTANCE) {
27612823
recordUnmount(instance);
2762-
} else {
2824+
} else if (instance.kind === VIRTUAL_INSTANCE) {
27632825
recordVirtualUnmount(instance);
2826+
} else {
2827+
(instance: FilteredFiberInstance); // assert exhaustive
27642828
}
27652829
removeChild(instance, null);
27662830
}
@@ -2865,7 +2929,9 @@ export function attach(
28652929
virtualInstance.treeBaseDuration = treeBaseDuration;
28662930
}
28672931

2868-
function recordResetChildren(parentInstance: DevToolsInstance) {
2932+
function recordResetChildren(
2933+
parentInstance: FiberInstance | VirtualInstance,
2934+
) {
28692935
if (__DEBUG__) {
28702936
if (
28712937
parentInstance.firstChild !== null &&
@@ -2885,7 +2951,17 @@ export function attach(
28852951

28862952
let child: null | DevToolsInstance = parentInstance.firstChild;
28872953
while (child !== null) {
2888-
nextChildren.push(child.id);
2954+
if (child.kind === FILTERED_FIBER_INSTANCE) {
2955+
for (
2956+
let innerChild: null | DevToolsInstance = parentInstance.firstChild;
2957+
innerChild !== null;
2958+
innerChild = innerChild.nextSibling
2959+
) {
2960+
nextChildren.push((innerChild: any).id);
2961+
}
2962+
} else {
2963+
nextChildren.push(child.id);
2964+
}
28892965
child = child.nextSibling;
28902966
}
28912967

@@ -3693,7 +3769,7 @@ export function attach(
36933769
devtoolsInstance: DevToolsInstance,
36943770
hostInstances: Array<HostInstance>,
36953771
) {
3696-
if (devtoolsInstance.kind === FIBER_INSTANCE) {
3772+
if (devtoolsInstance.kind !== VIRTUAL_INSTANCE) {
36973773
const fiber = devtoolsInstance.data;
36983774
appendHostInstancesByFiber(fiber, hostInstances);
36993775
return;
@@ -3907,7 +3983,7 @@ export function attach(
39073983
}
39083984

39093985
function instanceToSerializedElement(
3910-
instance: DevToolsInstance,
3986+
instance: FiberInstance | VirtualInstance,
39113987
): SerializedElement {
39123988
if (instance.kind === FIBER_INSTANCE) {
39133989
const fiber = instance.data;
@@ -4002,7 +4078,7 @@ export function attach(
40024078
function findNearestOwnerInstance(
40034079
parentInstance: null | DevToolsInstance,
40044080
owner: void | null | ReactComponentInfo | Fiber,
4005-
): null | DevToolsInstance {
4081+
): null | FiberInstance | VirtualInstance {
40064082
if (owner == null) {
40074083
return null;
40084084
}
@@ -4017,6 +4093,9 @@ export function attach(
40174093
// needs a duck type check anyway.
40184094
parentInstance.data === (owner: any).alternate
40194095
) {
4096+
if (parentInstance.kind === FILTERED_FIBER_INSTANCE) {
4097+
return null;
4098+
}
40204099
return parentInstance;
40214100
}
40224101
parentInstance = parentInstance.parent;
@@ -4094,7 +4173,11 @@ export function attach(
40944173
if (devtoolsInstance.kind === VIRTUAL_INSTANCE) {
40954174
return inspectVirtualInstanceRaw(devtoolsInstance);
40964175
}
4097-
return inspectFiberInstanceRaw(devtoolsInstance);
4176+
if (devtoolsInstance.kind === FIBER_INSTANCE) {
4177+
return inspectFiberInstanceRaw(devtoolsInstance);
4178+
}
4179+
(devtoolsInstance: FilteredFiberInstance); // assert exhaustive
4180+
throw new Error('Unsupported instance kind');
40984181
}
40994182

41004183
function inspectFiberInstanceRaw(
@@ -4397,7 +4480,7 @@ export function attach(
43974480
let targetErrorBoundaryID = null;
43984481
let parent = virtualInstance.parent;
43994482
while (parent !== null) {
4400-
if (parent.kind === FIBER_INSTANCE) {
4483+
if (parent.kind !== VIRTUAL_INSTANCE) {
44014484
targetErrorBoundaryID = getNearestErrorBoundaryID(parent.data);
44024485
let current = parent.data;
44034486
while (current.return !== null) {
@@ -5188,7 +5271,9 @@ export function attach(
51885271
) {
51895272
// We don't need to convert milliseconds to microseconds in this case,
51905273
// because the profiling summary is JSON serialized.
5191-
target.push([instance.id, instance.treeBaseDuration]);
5274+
if (instance.kind !== FILTERED_FIBER_INSTANCE) {
5275+
target.push([instance.id, instance.treeBaseDuration]);
5276+
}
51925277
for (
51935278
let child = instance.firstChild;
51945279
child !== null;
@@ -5402,7 +5487,7 @@ export function attach(
54025487
// In that case, we'll do some extra checks for matching mounts.
54035488
let trackedPath: Array<PathFrame> | null = null;
54045489
let trackedPathMatchFiber: Fiber | null = null; // This is the deepest unfiltered match of a Fiber.
5405-
let trackedPathMatchInstance: DevToolsInstance | null = null; // This is the deepest matched filtered Instance.
5490+
let trackedPathMatchInstance: FiberInstance | VirtualInstance | null = null; // This is the deepest matched filtered Instance.
54065491
let trackedPathMatchDepth = -1;
54075492
let mightBeOnTrackedPath = false;
54085493

@@ -5421,7 +5506,7 @@ export function attach(
54215506
// The return value signals whether we should keep matching siblings or not.
54225507
function updateTrackedPathStateBeforeMount(
54235508
fiber: Fiber,
5424-
fiberInstance: null | FiberInstance,
5509+
fiberInstance: null | FiberInstance | FilteredFiberInstance,
54255510
): boolean {
54265511
if (trackedPath === null || !mightBeOnTrackedPath) {
54275512
// Fast path: there's nothing to track so do nothing and ignore siblings.
@@ -5450,7 +5535,7 @@ export function attach(
54505535
) {
54515536
// We have our next match.
54525537
trackedPathMatchFiber = fiber;
5453-
if (fiberInstance !== null) {
5538+
if (fiberInstance !== null && fiberInstance.kind === FIBER_INSTANCE) {
54545539
trackedPathMatchInstance = fiberInstance;
54555540
}
54565541
trackedPathMatchDepth++;

0 commit comments

Comments
 (0)