[Flight] Emit Deduped Server Components Marker (#31737)

Stacked on #31736.

<img width="1223" alt="Screenshot 2024-12-11 at 8 21 12 PM"
src="https://github.com/user-attachments/assets/a7cbc04b-c831-476b-aa2f-baddec9461c9"
/>

This emits a placeholder when we're deduping a component. This starts
when the parent's self time ends, where we would've started rendering
this component if it wasn't already started. The end time is when the
actual render ends since the parent is also blocked by it.
This commit is contained in:
Sebastian Markbåge
2024-12-16 13:16:53 -05:00
committed by GitHub
parent 07facb52d3
commit bdf187174d
3 changed files with 60 additions and 6 deletions
+3 -2
View File
@@ -27,7 +27,8 @@ function Foo({children}) {
return <div>{children}</div>;
}
function Bar({children}) {
async function Bar({children}) {
await new Promise(resolve => setTimeout(() => resolve('deferred text'), 10));
return <div>{children}</div>;
}
@@ -81,7 +82,7 @@ export default async function App({prerender}) {
<Client />
<Note />
<Foo>{dedupedChild}</Foo>
<Bar>{dedupedChild}</Bar>
<Bar>{Promise.resolve([dedupedChild])}</Bar>
</Container>
</body>
</html>
+41 -4
View File
@@ -72,6 +72,7 @@ import {readTemporaryReference} from './ReactFlightTemporaryReferences';
import {
markAllTracksInOrder,
logComponentRender,
logDedupedComponentRender,
} from './ReactFlightPerformanceTrack';
import {
@@ -130,6 +131,7 @@ export type JSONValue =
type ProfilingResult = {
track: number,
endTime: number,
component: null | ReactComponentInfo,
};
const ROW_ID = 0;
@@ -647,7 +649,7 @@ export function reportGlobalError(response: Response, error: Error): void {
});
if (enableProfilerTimer && enableComponentPerformanceTrack) {
markAllTracksInOrder();
flushComponentPerformance(getChunk(response, 0), 0, -Infinity);
flushComponentPerformance(getChunk(response, 0), 0, -Infinity, -Infinity);
}
}
@@ -2748,7 +2750,8 @@ function resolveTypedArray(
function flushComponentPerformance(
root: SomeChunk<any>,
trackIdx: number, // Next available track
trackTime: number, // The time after which it is available
trackTime: number, // The time after which it is available,
parentEndTime: number,
): ProfilingResult {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
// eslint-disable-next-line react-internal/prod-error-codes
@@ -2765,6 +2768,22 @@ function flushComponentPerformance(
// chunk in two places. We should extend the current end time as if it was
// rendered as part of this tree.
const previousResult: ProfilingResult = root._children;
const previousEndTime = previousResult.endTime;
if (
parentEndTime > -Infinity &&
parentEndTime < previousEndTime &&
previousResult.component !== null
) {
// Log a placeholder for the deduped value under this child starting
// from the end of the self time of the parent and spanning until the
// the deduped end.
logDedupedComponentRender(
previousResult.component,
trackIdx,
parentEndTime,
previousEndTime,
);
}
// Since we didn't bump the track this time, we just return the same track.
previousResult.track = trackIdx;
return previousResult;
@@ -2792,15 +2811,27 @@ function flushComponentPerformance(
// The start time of this component is before the end time of the previous
// component on this track so we need to bump the next one to a parallel track.
trackIdx++;
trackTime = startTime;
}
trackTime = startTime;
break;
}
}
}
for (let i = debugInfo.length - 1; i >= 0; i--) {
const info = debugInfo[i];
if (typeof info.time === 'number') {
if (info.time > parentEndTime) {
parentEndTime = info.time;
}
}
}
}
const result: ProfilingResult = {track: trackIdx, endTime: -Infinity};
const result: ProfilingResult = {
track: trackIdx,
endTime: -Infinity,
component: null,
};
root._children = result;
let childrenEndTime = -Infinity;
let childTrackIdx = trackIdx;
@@ -2810,7 +2841,11 @@ function flushComponentPerformance(
children[i],
childTrackIdx,
childTrackTime,
parentEndTime,
);
if (childResult.component !== null) {
result.component = childResult.component;
}
childTrackIdx = childResult.track;
const childEndTime = childResult.endTime;
childTrackTime = childEndTime;
@@ -2842,6 +2877,8 @@ function flushComponentPerformance(
endTime,
childrenEndTime,
);
// Track the root most component of the result for deduping logging.
result.component = componentInfo;
}
}
}
@@ -90,3 +90,19 @@ export function logComponentRender(
performance.measure(name, reusableComponentOptions);
}
}
export function logDedupedComponentRender(
componentInfo: ReactComponentInfo,
trackIdx: number,
startTime: number,
endTime: number,
): void {
if (supportsUserTiming && endTime >= 0 && trackIdx < 10) {
const name = componentInfo.name;
reusableComponentDevToolDetails.color = 'tertiary-light';
reusableComponentDevToolDetails.track = trackNames[trackIdx];
reusableComponentOptions.start = startTime < 0 ? 0 : startTime;
reusableComponentOptions.end = endTime;
performance.measure(name + ' [deduped]', reusableComponentOptions);
}
}