@@ -146,6 +146,7 @@ import {formatOwnerStack} from '../shared/DevToolsOwnerStack';
146
146
// Kinds
147
147
const FIBER_INSTANCE = 0 ;
148
148
const VIRTUAL_INSTANCE = 1 ;
149
+ const FILTERED_FIBER_INSTANCE = 2 ;
149
150
150
151
// Flags
151
152
const FORCE_SUSPENSE_FALLBACK = /* */ 0b001 ;
@@ -157,9 +158,9 @@ const FORCE_ERROR_RESET = /* */ 0b100;
157
158
type FiberInstance = {
158
159
kind : 0 ,
159
160
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 ,
163
164
flags : number , // Force Error/Suspense
164
165
source : null | string | Error | Source , // source location of this component function, or owned child stack
165
166
errors : null | Map < string , number> , // error messages and count
@@ -184,6 +185,39 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
184
185
} ;
185
186
}
186
187
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
+
187
221
// This type represents a stateful instance of a Server Component or a Component
188
222
// that gets optimized away - e.g. call-through without creating a Fiber.
189
223
// It's basically a virtual Fiber. This is not a semantic concept in React.
@@ -192,9 +226,9 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
192
226
type VirtualInstance = {
193
227
kind : 1 ,
194
228
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 ,
198
232
flags : number ,
199
233
source : null | string | Error | Source , // source location of this server component, or owned child stack
200
234
// Errors and Warnings happen per ReactComponentInfo which can appear in
@@ -226,7 +260,7 @@ function createVirtualInstance(
226
260
} ;
227
261
}
228
262
229
- type DevToolsInstance = FiberInstance | VirtualInstance ;
263
+ type DevToolsInstance = FiberInstance | VirtualInstance | FilteredFiberInstance ;
230
264
231
265
type getDisplayNameForFiberType = ( fiber : Fiber ) => string | null ;
232
266
type getTypeSymbolType = ( type : any ) => symbol | number ;
@@ -736,7 +770,8 @@ const fiberToFiberInstanceMap: Map<Fiber, FiberInstance> = new Map();
736
770
// Map of id to one (arbitrary) Fiber in a pair.
737
771
// This Map is used to e.g. get the display name for a Fiber or schedule an update,
738
772
// 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 ( ) ;
740
775
741
776
// Map of canonical HostInstances to the nearest parent DevToolsInstance.
742
777
const publicInstanceToDevToolsInstanceMap : Map < HostInstance , DevToolsInstance > =
@@ -1141,13 +1176,22 @@ export function attach(
1141
1176
function debugTree ( instance : DevToolsInstance , indent : number = 0 ) {
1142
1177
if ( __DEBUG__ ) {
1143
1178
const name =
1144
- ( instance . kind === FIBER_INSTANCE
1179
+ ( instance . kind !== VIRTUAL_INSTANCE
1145
1180
? getDisplayNameForFiber ( instance . data )
1146
1181
: instance . data . name ) || '' ;
1147
1182
console . log (
1148
- ' ' . repeat ( indent ) + '- ' + instance . id + ' (' + name + ')' ,
1183
+ ' ' . repeat ( indent ) +
1184
+ '- ' +
1185
+ ( instance . kind === FILTERED_FIBER_INSTANCE ? 0 : instance . id ) +
1186
+ ' (' +
1187
+ name +
1188
+ ')' ,
1149
1189
'parent' ,
1150
- instance . parent === null ? ' ' : instance . parent . id ,
1190
+ instance . parent === null
1191
+ ? ' '
1192
+ : instance . parent . kind === FILTERED_FIBER_INSTANCE
1193
+ ? 0
1194
+ : instance . parent . id ,
1151
1195
'next' ,
1152
1196
instance . nextSibling === null ? ' ' : instance . nextSibling . id ,
1153
1197
) ;
@@ -2264,7 +2308,12 @@ export function attach(
2264
2308
ownerInstance . source = fiber . _debugStack ;
2265
2309
}
2266
2310
const ownerID = ownerInstance === null ? 0 : ownerInstance . id ;
2267
- const parentID = parentInstance ? parentInstance . id : 0 ;
2311
+ const parentID = parentInstance
2312
+ ? parentInstance . kind === FILTERED_FIBER_INSTANCE
2313
+ ? // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
2314
+ ( ( parentInstance . parent : any ) : VirtualInstance ) . id
2315
+ : parentInstance . id
2316
+ : 0 ;
2268
2317
2269
2318
const displayNameStringID = getStringID ( displayName ) ;
2270
2319
@@ -2348,7 +2397,12 @@ export function attach(
2348
2397
ownerInstance . source = componentInfo . debugStack ;
2349
2398
}
2350
2399
const ownerID = ownerInstance === null ? 0 : ownerInstance . id ;
2351
- const parentID = parentInstance ? parentInstance . id : 0 ;
2400
+ const parentID = parentInstance
2401
+ ? parentInstance . kind === FILTERED_FIBER_INSTANCE
2402
+ ? // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
2403
+ ( ( parentInstance . parent : any ) : VirtualInstance ) . id
2404
+ : parentInstance . id
2405
+ : 0 ;
2352
2406
2353
2407
const displayNameStringID = getStringID ( displayName ) ;
2354
2408
@@ -2713,6 +2767,14 @@ export function attach(
2713
2767
if ( shouldIncludeInTree ) {
2714
2768
newInstance = recordMount ( fiber , reconcilingParent ) ;
2715
2769
insertChild ( newInstance ) ;
2770
+ } else if (
2771
+ reconcilingParent !== null &&
2772
+ reconcilingParent . kind === VIRTUAL_INSTANCE
2773
+ ) {
2774
+ // If the parent is a Virtual Instance and we filtered this Fiber we include a
2775
+ // hidden node.
2776
+ newInstance = createFilteredFiberInstance ( fiber ) ;
2777
+ insertChild ( newInstance ) ;
2716
2778
}
2717
2779
2718
2780
// If we have the tree selection from previous reload, try to match this Fiber.
@@ -2725,7 +2787,7 @@ export function attach(
2725
2787
const stashedParent = reconcilingParent ;
2726
2788
const stashedPrevious = previouslyReconciledSibling ;
2727
2789
const stashedRemaining = remainingReconcilingChildren ;
2728
- if ( shouldIncludeInTree ) {
2790
+ if ( newInstance !== null ) {
2729
2791
// Push a new DevTools instance parent while reconciling this subtree.
2730
2792
reconcilingParent = newInstance ;
2731
2793
previouslyReconciledSibling = null ;
@@ -2810,7 +2872,7 @@ export function attach(
2810
2872
}
2811
2873
}
2812
2874
} finally {
2813
- if ( shouldIncludeInTree ) {
2875
+ if ( newInstance !== null ) {
2814
2876
reconcilingParent = stashedParent ;
2815
2877
previouslyReconciledSibling = stashedPrevious ;
2816
2878
remainingReconcilingChildren = stashedRemaining ;
@@ -2850,8 +2912,10 @@ export function attach(
2850
2912
}
2851
2913
if ( instance . kind === FIBER_INSTANCE ) {
2852
2914
recordUnmount ( instance ) ;
2853
- } else {
2915
+ } else if ( instance . kind === VIRTUAL_INSTANCE ) {
2854
2916
recordVirtualUnmount ( instance ) ;
2917
+ } else {
2918
+ untrackFiber ( instance , instance . data ) ;
2855
2919
}
2856
2920
removeChild ( instance , null ) ;
2857
2921
}
@@ -2956,7 +3020,9 @@ export function attach(
2956
3020
virtualInstance . treeBaseDuration = treeBaseDuration ;
2957
3021
}
2958
3022
2959
- function recordResetChildren ( parentInstance : DevToolsInstance ) {
3023
+ function recordResetChildren (
3024
+ parentInstance : FiberInstance | VirtualInstance ,
3025
+ ) {
2960
3026
if ( __DEBUG__ ) {
2961
3027
if (
2962
3028
parentInstance . firstChild !== null &&
@@ -2976,7 +3042,17 @@ export function attach(
2976
3042
2977
3043
let child : null | DevToolsInstance = parentInstance . firstChild ;
2978
3044
while ( child !== null ) {
2979
- nextChildren . push ( child . id ) ;
3045
+ if ( child . kind === FILTERED_FIBER_INSTANCE ) {
3046
+ for (
3047
+ let innerChild : null | DevToolsInstance = parentInstance . firstChild ;
3048
+ innerChild !== null ;
3049
+ innerChild = innerChild . nextSibling
3050
+ ) {
3051
+ nextChildren . push ( ( innerChild : any ) . id ) ;
3052
+ }
3053
+ } else {
3054
+ nextChildren . push ( child . id ) ;
3055
+ }
2980
3056
child = child . nextSibling ;
2981
3057
}
2982
3058
@@ -3788,7 +3864,7 @@ export function attach(
3788
3864
devtoolsInstance : DevToolsInstance ,
3789
3865
hostInstances : Array < HostInstance > ,
3790
3866
) {
3791
- if ( devtoolsInstance . kind === FIBER_INSTANCE ) {
3867
+ if ( devtoolsInstance . kind !== VIRTUAL_INSTANCE ) {
3792
3868
const fiber = devtoolsInstance . data ;
3793
3869
appendHostInstancesByFiber ( fiber , hostInstances ) ;
3794
3870
return ;
@@ -3889,6 +3965,10 @@ export function attach(
3889
3965
): number | null {
3890
3966
const instance = publicInstanceToDevToolsInstanceMap . get ( publicInstance ) ;
3891
3967
if ( instance !== undefined ) {
3968
+ if ( instance . kind === FILTERED_FIBER_INSTANCE ) {
3969
+ // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
3970
+ return ( ( instance . parent : any ) : VirtualInstance ) . id ;
3971
+ }
3892
3972
return instance . id ;
3893
3973
}
3894
3974
return null ;
@@ -3941,7 +4021,7 @@ export function attach(
3941
4021
}
3942
4022
3943
4023
function instanceToSerializedElement (
3944
- instance : DevToolsInstance ,
4024
+ instance : FiberInstance | VirtualInstance ,
3945
4025
) : SerializedElement {
3946
4026
if ( instance . kind === FIBER_INSTANCE ) {
3947
4027
const fiber = instance . data ;
@@ -4036,7 +4116,7 @@ export function attach(
4036
4116
function findNearestOwnerInstance (
4037
4117
parentInstance : null | DevToolsInstance ,
4038
4118
owner : void | null | ReactComponentInfo | Fiber ,
4039
- ) : null | DevToolsInstance {
4119
+ ) : null | FiberInstance | VirtualInstance {
4040
4120
if ( owner == null ) {
4041
4121
return null ;
4042
4122
}
@@ -4051,6 +4131,9 @@ export function attach(
4051
4131
// needs a duck type check anyway.
4052
4132
parentInstance . data === ( owner : any ) . alternate
4053
4133
) {
4134
+ if ( parentInstance . kind === FILTERED_FIBER_INSTANCE ) {
4135
+ return null ;
4136
+ }
4054
4137
return parentInstance;
4055
4138
}
4056
4139
parentInstance = parentInstance . parent ;
@@ -4128,7 +4211,11 @@ export function attach(
4128
4211
if (devtoolsInstance.kind === VIRTUAL_INSTANCE) {
4129
4212
return inspectVirtualInstanceRaw ( devtoolsInstance ) ;
4130
4213
}
4131
- return inspectFiberInstanceRaw(devtoolsInstance);
4214
+ if (devtoolsInstance.kind === FIBER_INSTANCE) {
4215
+ return inspectFiberInstanceRaw ( devtoolsInstance ) ;
4216
+ }
4217
+ (devtoolsInstance: FilteredFiberInstance); // assert exhaustive
4218
+ throw new Error('Unsupported instance kind');
4132
4219
}
4133
4220
4134
4221
function inspectFiberInstanceRaw (
@@ -4431,7 +4518,7 @@ export function attach(
4431
4518
let targetErrorBoundaryID = null ;
4432
4519
let parent = virtualInstance . parent ;
4433
4520
while ( parent !== null ) {
4434
- if ( parent . kind === FIBER_INSTANCE ) {
4521
+ if ( parent . kind !== VIRTUAL_INSTANCE ) {
4435
4522
targetErrorBoundaryID = getNearestErrorBoundaryID ( parent . data ) ;
4436
4523
let current = parent . data ;
4437
4524
while ( current . return !== null ) {
@@ -5222,7 +5309,9 @@ export function attach(
5222
5309
) {
5223
5310
// We don't need to convert milliseconds to microseconds in this case,
5224
5311
// because the profiling summary is JSON serialized.
5225
- target . push ( [ instance . id , instance . treeBaseDuration ] ) ;
5312
+ if ( instance . kind !== FILTERED_FIBER_INSTANCE ) {
5313
+ target . push ( [ instance . id , instance . treeBaseDuration ] ) ;
5314
+ }
5226
5315
for (
5227
5316
let child = instance.firstChild;
5228
5317
child !== null;
@@ -5436,7 +5525,7 @@ export function attach(
5436
5525
// In that case, we'll do some extra checks for matching mounts.
5437
5526
let trackedPath : Array < PathFrame > | null = null;
5438
5527
let trackedPathMatchFiber: Fiber | null = null; // This is the deepest unfiltered match of a Fiber.
5439
- let trackedPathMatchInstance: DevToolsInstance | null = null; // This is the deepest matched filtered Instance.
5528
+ let trackedPathMatchInstance: FiberInstance | VirtualInstance | null = null; // This is the deepest matched filtered Instance.
5440
5529
let trackedPathMatchDepth = -1;
5441
5530
let mightBeOnTrackedPath = false;
5442
5531
@@ -5455,7 +5544,7 @@ export function attach(
5455
5544
// The return value signals whether we should keep matching siblings or not.
5456
5545
function updateTrackedPathStateBeforeMount (
5457
5546
fiber : Fiber ,
5458
- fiberInstance : null | FiberInstance ,
5547
+ fiberInstance : null | FiberInstance | FilteredFiberInstance ,
5459
5548
) : boolean {
5460
5549
if ( trackedPath === null || ! mightBeOnTrackedPath ) {
5461
5550
// Fast path: there's nothing to track so do nothing and ignore siblings.
@@ -5484,7 +5573,7 @@ export function attach(
5484
5573
) {
5485
5574
// We have our next match.
5486
5575
trackedPathMatchFiber = fiber ;
5487
- if ( fiberInstance !== null ) {
5576
+ if ( fiberInstance !== null && fiberInstance . kind === FIBER_INSTANCE ) {
5488
5577
trackedPathMatchInstance = fiberInstance ;
5489
5578
}
5490
5579
trackedPathMatchDepth ++ ;
0 commit comments