diff --git a/fixtures/flight/src/App.js b/fixtures/flight/src/App.js index 49bfc9e05135c..69fbb5e0af97d 100644 --- a/fixtures/flight/src/App.js +++ b/fixtures/flight/src/App.js @@ -27,7 +27,8 @@ function Foo({children}) { return
{children}
; } -function Bar({children}) { +async function Bar({children}) { + await new Promise(resolve => setTimeout(() => resolve('deferred text'), 10)); return
{children}
; } @@ -81,7 +82,7 @@ export default async function App({prerender}) { {dedupedChild} - {dedupedChild} + {Promise.resolve([dedupedChild])} diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index ccb8632289f20..52c7ec73a4c41 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -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, 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; } } } diff --git a/packages/react-client/src/ReactFlightPerformanceTrack.js b/packages/react-client/src/ReactFlightPerformanceTrack.js index cf78f7d7de03c..cfd8ca96b3359 100644 --- a/packages/react-client/src/ReactFlightPerformanceTrack.js +++ b/packages/react-client/src/ReactFlightPerformanceTrack.js @@ -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); + } +}