Skip to content

Commit 84e4b52

Browse files
committed
Log the previously rendered component as a deduped entry
1 parent 70facac commit 84e4b52

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

fixtures/flight/src/App.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ function Foo({children}) {
2727
return <div>{children}</div>;
2828
}
2929

30-
function Bar({children}) {
30+
async function Bar({children}) {
31+
await new Promise(resolve => setTimeout(() => resolve('deferred text'), 10));
3132
return <div>{children}</div>;
3233
}
3334

@@ -81,7 +82,7 @@ export default async function App({prerender}) {
8182
<Client />
8283
<Note />
8384
<Foo>{dedupedChild}</Foo>
84-
<Bar>{dedupedChild}</Bar>
85+
<Bar>{Promise.resolve([dedupedChild])}</Bar>
8586
</Container>
8687
</body>
8788
</html>

packages/react-client/src/ReactFlightClient.js

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {readTemporaryReference} from './ReactFlightTemporaryReferences';
7272
import {
7373
markAllTracksInOrder,
7474
logComponentRender,
75+
logDedupedComponentRender,
7576
} from './ReactFlightPerformanceTrack';
7677

7778
import {
@@ -130,6 +131,7 @@ export type JSONValue =
130131
type ProfilingResult = {
131132
track: number,
132133
endTime: number,
134+
component: null | ReactComponentInfo,
133135
};
134136

135137
const ROW_ID = 0;
@@ -647,7 +649,7 @@ export function reportGlobalError(response: Response, error: Error): void {
647649
});
648650
if (enableProfilerTimer && enableComponentPerformanceTrack) {
649651
markAllTracksInOrder();
650-
flushComponentPerformance(getChunk(response, 0), 0, -Infinity);
652+
flushComponentPerformance(getChunk(response, 0), 0, -Infinity, -Infinity);
651653
}
652654
}
653655

@@ -2748,7 +2750,8 @@ function resolveTypedArray(
27482750
function flushComponentPerformance(
27492751
root: SomeChunk<any>,
27502752
trackIdx: number, // Next available track
2751-
trackTime: number, // The time after which it is available
2753+
trackTime: number, // The time after which it is available,
2754+
parentEndTime: number,
27522755
): ProfilingResult {
27532756
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
27542757
// eslint-disable-next-line react-internal/prod-error-codes
@@ -2765,6 +2768,22 @@ function flushComponentPerformance(
27652768
// chunk in two places. We should extend the current end time as if it was
27662769
// rendered as part of this tree.
27672770
const previousResult: ProfilingResult = root._children;
2771+
const previousEndTime = previousResult.endTime;
2772+
if (
2773+
parentEndTime > -Infinity &&
2774+
parentEndTime < previousEndTime &&
2775+
previousResult.component !== null
2776+
) {
2777+
// Log a placeholder for the deduped value under this child starting
2778+
// from the end of the self time of the parent and spanning until the
2779+
// the deduped end.
2780+
logDedupedComponentRender(
2781+
previousResult.component,
2782+
trackIdx,
2783+
parentEndTime,
2784+
previousEndTime,
2785+
);
2786+
}
27682787
// Since we didn't bump the track this time, we just return the same track.
27692788
previousResult.track = trackIdx;
27702789
return previousResult;
@@ -2792,15 +2811,27 @@ function flushComponentPerformance(
27922811
// The start time of this component is before the end time of the previous
27932812
// component on this track so we need to bump the next one to a parallel track.
27942813
trackIdx++;
2795-
trackTime = startTime;
27962814
}
2815+
trackTime = startTime;
27972816
break;
27982817
}
27992818
}
28002819
}
2820+
for (let i = debugInfo.length - 1; i >= 0; i--) {
2821+
const info = debugInfo[i];
2822+
if (typeof info.time === 'number') {
2823+
if (info.time > parentEndTime) {
2824+
parentEndTime = info.time;
2825+
}
2826+
}
2827+
}
28012828
}
28022829

2803-
const result: ProfilingResult = {track: trackIdx, endTime: -Infinity};
2830+
const result: ProfilingResult = {
2831+
track: trackIdx,
2832+
endTime: -Infinity,
2833+
component: null,
2834+
};
28042835
root._children = result;
28052836
let childrenEndTime = -Infinity;
28062837
let childTrackIdx = trackIdx;
@@ -2810,7 +2841,11 @@ function flushComponentPerformance(
28102841
children[i],
28112842
childTrackIdx,
28122843
childTrackTime,
2844+
parentEndTime,
28132845
);
2846+
if (childResult.component !== null) {
2847+
result.component = childResult.component;
2848+
}
28142849
childTrackIdx = childResult.track;
28152850
const childEndTime = childResult.endTime;
28162851
childTrackTime = childEndTime;
@@ -2842,6 +2877,8 @@ function flushComponentPerformance(
28422877
endTime,
28432878
childrenEndTime,
28442879
);
2880+
// Track the root most component of the result for deduping logging.
2881+
result.component = componentInfo;
28452882
}
28462883
}
28472884
}

packages/react-client/src/ReactFlightPerformanceTrack.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,19 @@ export function logComponentRender(
9090
performance.measure(name, reusableComponentOptions);
9191
}
9292
}
93+
94+
export function logDedupedComponentRender(
95+
componentInfo: ReactComponentInfo,
96+
trackIdx: number,
97+
startTime: number,
98+
endTime: number,
99+
): void {
100+
if (supportsUserTiming && endTime >= 0 && trackIdx < 10) {
101+
const name = componentInfo.name;
102+
reusableComponentDevToolDetails.color = 'tertiary-light';
103+
reusableComponentDevToolDetails.track = trackNames[trackIdx];
104+
reusableComponentOptions.start = startTime < 0 ? 0 : startTime;
105+
reusableComponentOptions.end = endTime;
106+
performance.measure(name + ' [deduped]', reusableComponentOptions);
107+
}
108+
}

0 commit comments

Comments
 (0)