diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 8d2c215a6b9..3385a3d6327 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -78,6 +78,7 @@ import { logComponentRender, logDedupedComponentRender, logComponentErrored, + logIOInfo, } from './ReactFlightPerformanceTrack'; import { @@ -2769,6 +2770,8 @@ function initializeIOInfo(response: Response, ioInfo: ReactIOInfo): void { ioInfo.start += response._timeOrigin; // $FlowFixMe[cannot-write] ioInfo.end += response._timeOrigin; + + logIOInfo(ioInfo); } function resolveIOInfo( @@ -2890,6 +2893,7 @@ function flushComponentPerformance( trackIdx, parentEndTime, previousEndTime, + response._rootEnvironmentName, ); } // Since we didn't bump the track this time, we just return the same track. diff --git a/packages/react-client/src/ReactFlightPerformanceTrack.js b/packages/react-client/src/ReactFlightPerformanceTrack.js index ed0f67a4f31..8284ac8b6e4 100644 --- a/packages/react-client/src/ReactFlightPerformanceTrack.js +++ b/packages/react-client/src/ReactFlightPerformanceTrack.js @@ -9,7 +9,7 @@ /* eslint-disable react-internal/no-production-logging */ -import type {ReactComponentInfo} from 'shared/ReactTypes'; +import type {ReactComponentInfo, ReactIOInfo} from 'shared/ReactTypes'; import {enableProfilerTimer} from 'shared/ReactFeatureFlags'; @@ -18,6 +18,7 @@ const supportsUserTiming = typeof console !== 'undefined' && typeof console.timeStamp === 'function'; +const IO_TRACK = 'Server Requests ⚛'; const COMPONENTS_TRACK = 'Server Components ⚛'; export function markAllTracksInOrder() { @@ -25,6 +26,14 @@ export function markAllTracksInOrder() { // Ensure we create the Server Component track groups earlier than the Client Scheduler // and Client Components. We can always add the 0 time slot even if it's in the past. // That's still considered for ordering. + console.timeStamp( + 'Server Requests Track', + 0.001, + 0.001, + IO_TRACK, + undefined, + 'primary-light', + ); console.timeStamp( 'Server Components Track', 0.001, @@ -166,9 +175,13 @@ export function logDedupedComponentRender( trackIdx: number, startTime: number, endTime: number, + rootEnv: string, ): void { if (supportsUserTiming && endTime >= 0 && trackIdx < 10) { + const env = componentInfo.env; const name = componentInfo.name; + const isPrimaryEnv = env === rootEnv; + const color = isPrimaryEnv ? 'primary-light' : 'secondary-light'; const entryName = name + ' [deduped]'; const debugTask = componentInfo.debugTask; if (__DEV__ && debugTask) { @@ -181,7 +194,7 @@ export function logDedupedComponentRender( endTime, trackNames[trackIdx], COMPONENTS_TRACK, - 'tertiary-light', + color, ), ); } else { @@ -191,7 +204,54 @@ export function logDedupedComponentRender( endTime, trackNames[trackIdx], COMPONENTS_TRACK, - 'tertiary-light', + color, + ); + } + } +} + +function getIOColor( + functionName: string, +): 'tertiary-light' | 'tertiary' | 'tertiary-dark' { + // Add some color variation to be able to distinguish various sources. + switch (functionName.charCodeAt(0) % 3) { + case 0: + return 'tertiary-light'; + case 1: + return 'tertiary'; + default: + return 'tertiary-dark'; + } +} + +export function logIOInfo(ioInfo: ReactIOInfo): void { + const startTime = ioInfo.start; + const endTime = ioInfo.end; + if (supportsUserTiming && endTime >= 0) { + const name = ioInfo.name; + const debugTask = ioInfo.debugTask; + const color = getIOColor(name); + if (__DEV__ && debugTask) { + debugTask.run( + // $FlowFixMe[method-unbinding] + console.timeStamp.bind( + console, + name, + startTime < 0 ? 0 : startTime, + endTime, + IO_TRACK, + undefined, + color, + ), + ); + } else { + console.timeStamp( + name, + startTime < 0 ? 0 : startTime, + endTime, + IO_TRACK, + undefined, + color, ); } }