@samitouri / QOS-React / commits / eec50b17b3

[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 });