[Flight] Only use debug component info for parent stacks (#34431)
Sebastian "Sebbie" Silbermann committed
Sep 9, 2025 at 19:58 UTC
eec50b17b38ac7c051804acfe46afabef9933ff4
2 files changed
+123
-18
packages/react-client/src/ReactFlightClient.js
+12
-4
@@ -1794,13 +1794,21 @@ function transferReferencedDebugInfo(
1794
existingDebugInfo.push.apply(existingDebugInfo, referencedDebugInfo);
1795
}
1796
}
1797
- // We also add it to the initializing chunk since the resolution of that promise is
1798
- // also blocked by these. By adding it to both we can track it even if the array/element
1797
+ // We also add the debug info to the initializing chunk since the resolution of that promise is
1798
+ // also blocked by the referenced debug info. By adding it to both we can track it even if the array/element
1799
// is extracted, or if the root is rendered as is.
1800
if (parentChunk !== null) {
1801
const parentDebugInfo = parentChunk._debugInfo;
1802
- // $FlowFixMe[method-unbinding]
1803
- parentDebugInfo.push.apply(parentDebugInfo, referencedDebugInfo);
1802
+ for (let i = 0; i < referencedDebugInfo.length; ++i) {
1803
+ const debugInfoEntry = referencedDebugInfo[i];
1804
+ if (debugInfoEntry.name != null) {
1805
+ (debugInfoEntry: ReactComponentInfo);
1806
+ // We're not transferring Component info since we use Component info
1807
+ // in Debug info to fill in gaps between Fibers for the parent stack.
1808
+ } else {
1809
+ parentDebugInfo.push(debugInfoEntry);
1810
+ }
1811
+ }
1812
}
1813
}
1814
}
packages/react-client/src/__tests__/ReactFlight-test.js
+111
-14
@@ -2960,13 +2960,6 @@ describe('ReactFlight', () => {
2960
{
2961
time: 16,
2962
},
2963
- {
2964
- env: 'third-party',
2965
- key: null,
2966
- name: 'ThirdPartyAsyncIterableComponent',
2967
- props: {},
2968
- stack: ' in Object.<anonymous> (at **)',
2969
- },
2963
{
2964
time: 16,
2965
},
@@ -2995,13 +2988,6 @@ describe('ReactFlight', () => {
2988
{
2989
time: 19,
2990
},
2998
- {
2999
- env: 'third-party',
3000
- key: null,
3001
- name: 'ThirdPartyAsyncIterableComponent',
3002
- props: {},
3003
- stack: ' in Object.<anonymous> (at **)',
3004
- },
2991
{time: 19},
2992
]
2993
: undefined,
@@ -3847,4 +3833,115 @@ describe('ReactFlight', () => {
3833
3834
expect(ReactNoop).toMatchRenderedOutput(<div>not using props</div>);
3835
});
3836
+
3837
+ // @gate !__DEV__ || enableComponentPerformanceTrack
3838
+ it('produces correct parent stacks', async () => {
3839
+ function Container() {
3840
+ return ReactServer.createElement('div', null);
3841
+ }
3842
+ function ContainerParent() {
3843
+ return ReactServer.createElement(Container, null);
3844
+ }
3845
+ function App() {
3846
+ return ReactServer.createElement(
3847
+ 'main',
3848
+ null,
3849
+ ReactServer.createElement(ContainerParent, null),
3850
+ );
3851
+ }
3852
+
3853
+ const transport = ReactNoopFlightServer.render({
3854
+ root: ReactServer.createElement(App, null),
3855
+ });
3856
+
3857
+ await act(async () => {
3858
+ const {root} = await ReactNoopFlightClient.read(transport);
3859
+
3860
+ ReactNoop.render(root);
3861
+
3862
+ expect(root.type).toBe('main');
3863
+ if (__DEV__) {
3864
+ const div = root.props.children;
3865
+ expect(getDebugInfo(div)).toEqual([
3866
+ {
3867
+ time: 14,
3868
+ },
3869
+ {
3870
+ env: 'Server',
3871
+ key: null,
3872
+ name: 'ContainerParent',
3873
+ owner: {
3874
+ env: 'Server',
3875
+ key: null,
3876
+ name: 'App',
3877
+ props: {},
3878
+ stack: ' in Object.<anonymous> (at **)',
3879
+ },
3880
+ props: {},
3881
+ stack: ' in App (at **)',
3882
+ },
3883
+ {
3884
+ time: 15,
3885
+ },
3886
+ {
3887
+ env: 'Server',
3888
+ key: null,
3889
+ name: 'Container',
3890
+ owner: {
3891
+ env: 'Server',
3892
+ key: null,
3893
+ name: 'ContainerParent',
3894
+ owner: {
3895
+ env: 'Server',
3896
+ key: null,
3897
+ name: 'App',
3898
+ props: {},
3899
+ stack: ' in Object.<anonymous> (at **)',
3900
+ },
3901
+ props: {},
3902
+ stack: ' in App (at **)',
3903
+ },
3904
+ props: {},
3905
+ stack: ' in ContainerParent (at **)',
3906
+ },
3907
+ {
3908
+ time: 16,
3909
+ },
3910
+ ]);
3911
+ expect(getDebugInfo(root)).toEqual([
3912
+ {
3913
+ time: 12,
3914
+ },
3915
+ {
3916
+ env: 'Server',
3917
+ key: null,
3918
+ name: 'App',
3919
+ props: {},
3920
+ stack: ' in Object.<anonymous> (at **)',
3921
+ },
3922
+ {
3923
+ time: 13,
3924
+ },
3925
+ {
3926
+ time: 14,
3927
+ },
3928
+ {
3929
+ time: 15,
3930
+ },
3931
+ {
3932
+ time: 16,
3933
+ },
3934
+ ]);
3935
+ } else {
3936
+ expect(root._debugInfo).toBe(undefined);
3937
+ expect(root._owner).toBe(undefined);
3938
+ }
3939
+ });
3940
+
3941
+ expect(ReactNoop).toMatchRenderedOutput(
3942
+ <main>
3943
+ <div />
3944
+ </main>,
3945
+ );
3946
+ });
3947
});