From 262c16349aa07f82ea2a4f53f35aa297ff749fbc Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 20 Dec 2024 13:36:37 -0500 Subject: [PATCH 1/5] Move logComponentRender into the branches These are the only ones marked with PerformedWork atm anyway. This lets us customize the logging for each branch. --- .../src/ReactFiberCommitWork.js | 67 +++++++++++++------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 43b726e981007..4ec7c04939b92 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -2702,25 +2702,6 @@ function commitPassiveMountOnFiber( ): void { const prevEffectStart = pushComponentEffectStart(); - // If this component rendered in Profiling mode (DEV or in Profiler component) then log its - // render time. We do this after the fact in the passive effect to avoid the overhead of this - // getting in the way of the render characteristics and avoid the overhead of unwinding - // uncommitted renders. - if ( - enableProfilerTimer && - enableComponentPerformanceTrack && - (finishedWork.mode & ProfileMode) !== NoMode && - ((finishedWork.actualStartTime: any): number) > 0 && - (finishedWork.flags & PerformedWork) !== NoFlags - ) { - logComponentRender( - finishedWork, - ((finishedWork.actualStartTime: any): number), - endTime, - inHydratedSubtree, - ); - } - // When updating this function, also update reconnectPassiveEffects, which does // most of the same things when an offscreen tree goes from hidden -> visible, // or when toggling effects inside a hidden tree. @@ -2729,6 +2710,25 @@ function commitPassiveMountOnFiber( case FunctionComponent: case ForwardRef: case SimpleMemoComponent: { + // If this component rendered in Profiling mode (DEV or in Profiler component) then log its + // render time. We do this after the fact in the passive effect to avoid the overhead of this + // getting in the way of the render characteristics and avoid the overhead of unwinding + // uncommitted renders. + if ( + enableProfilerTimer && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + ((finishedWork.actualStartTime: any): number) > 0 && + (finishedWork.flags & PerformedWork) !== NoFlags + ) { + logComponentRender( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + inHydratedSubtree, + ); + } + recursivelyTraversePassiveMountEffects( finishedRoot, finishedWork, @@ -2744,6 +2744,35 @@ function commitPassiveMountOnFiber( } break; } + case ClassComponent: { + // If this component rendered in Profiling mode (DEV or in Profiler component) then log its + // render time. We do this after the fact in the passive effect to avoid the overhead of this + // getting in the way of the render characteristics and avoid the overhead of unwinding + // uncommitted renders. + if ( + enableProfilerTimer && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + ((finishedWork.actualStartTime: any): number) > 0 && + (finishedWork.flags & PerformedWork) !== NoFlags + ) { + logComponentRender( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + inHydratedSubtree, + ); + } + + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + endTime, + ); + break; + } case HostRoot: { const prevEffectDuration = pushNestedEffectDurations(); From aeb3c411e7443f2da122d4c3f8791d833f0954bf Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 20 Dec 2024 13:49:55 -0500 Subject: [PATCH 2/5] Mark error boundarys as errored when they catch an error Ideally we'd be able to mark the component that errored but we don't commit the failed tree. In principle we could maybe walk the work in progress. --- .../src/ReactFiberCommitWork.js | 31 +++++++++++++------ .../src/ReactFiberPerformanceTrack.js | 16 ++++++++-- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 4ec7c04939b92..f37f7c3c243a1 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -98,6 +98,7 @@ import { Cloned, PerformedWork, ForceClientRender, + DidCapture, } from './ReactFiberFlags'; import { commitStartTime, @@ -113,8 +114,8 @@ import { } from './ReactProfilerTimer'; import { logComponentRender, + logComponentErrored, logComponentEffect, - logSuspenseBoundaryClientRendered, } from './ReactFiberPerformanceTrack'; import {ConcurrentMode, NoMode, ProfileMode} from './ReactTypeOfMode'; import {deferHiddenCallbacks} from './ReactFiberClassUpdateQueue'; @@ -2753,15 +2754,25 @@ function commitPassiveMountOnFiber( enableProfilerTimer && enableComponentPerformanceTrack && (finishedWork.mode & ProfileMode) !== NoMode && - ((finishedWork.actualStartTime: any): number) > 0 && - (finishedWork.flags & PerformedWork) !== NoFlags + ((finishedWork.actualStartTime: any): number) > 0 ) { - logComponentRender( - finishedWork, - ((finishedWork.actualStartTime: any): number), - endTime, - inHydratedSubtree, - ); + if ((finishedWork.flags & DidCapture) !== NoFlags) { + logComponentErrored( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + // TODO: The captured values are all hidden inside the updater/callback closures so + // we can't get to the errors but they're there so we should be able to log them. + [], + ); + } else if ((finishedWork.flags & PerformedWork) !== NoFlags) { + logComponentRender( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + inHydratedSubtree, + ); + } } recursivelyTraversePassiveMountEffects( @@ -2920,7 +2931,7 @@ function commitPassiveMountOnFiber( // rendered boundary. Such as postpone. if (hydrationErrors !== null) { const startTime: number = (finishedWork.actualStartTime: any); - logSuspenseBoundaryClientRendered( + logComponentErrored( finishedWork, startTime, endTime, diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 61bfd5cf7f844..fa78f6cce4a1a 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -13,6 +13,8 @@ import type {Lanes} from './ReactFiberLane'; import type {CapturedValue} from './ReactCapturedValue'; +import {SuspenseComponent} from './ReactWorkTags'; + import getComponentNameFromFiber from './getComponentNameFromFiber'; import { @@ -159,13 +161,18 @@ export function logComponentRender( } } -export function logSuspenseBoundaryClientRendered( +export function logComponentErrored( fiber: Fiber, startTime: number, endTime: number, errors: Array>, ): void { if (supportsUserTiming) { + const name = getComponentNameFromFiber(fiber); + if (name === null) { + // Skip + return; + } const properties = []; if (__DEV__) { for (let i = 0; i < errors.length; i++) { @@ -182,14 +189,17 @@ export function logSuspenseBoundaryClientRendered( properties.push(['Error', message]); } } - performance.measure('Suspense', { + performance.measure(name, { start: startTime, end: endTime, detail: { devtools: { color: 'error', track: COMPONENTS_TRACK, - tooltipText: 'Hydration failed', + tooltipText: + fiber.tag === SuspenseComponent + ? 'Hydration failed' + : 'Error boundary caught an error', properties, }, }, From ead40b28fd5a86023ad5b45e5016ad3bd2f7d611 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 20 Dec 2024 14:37:10 -0500 Subject: [PATCH 3/5] Mark the component that errored during the commit phase We also keep track of the errors and log those. --- .../src/ReactFiberCommitWork.js | 35 ++++++++++---- .../src/ReactFiberPerformanceTrack.js | 48 +++++++++++++++++++ .../src/ReactFiberWorkLoop.js | 7 +++ .../src/ReactProfilerTimer.js | 31 ++++++++++++ 4 files changed, 113 insertions(+), 8 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index f37f7c3c243a1..a244c65e3e886 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -108,9 +108,12 @@ import { resetComponentEffectTimers, pushComponentEffectStart, popComponentEffectStart, + pushComponentEffectErrors, + popComponentEffectErrors, componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, } from './ReactProfilerTimer'; import { logComponentRender, @@ -396,7 +399,7 @@ function commitLayoutEffectOnFiber( committedLanes: Lanes, ): void { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); // When updating this function, also update reappearLayoutEffects, which does // most of the same things when an offscreen tree goes from hidden -> visible. const flags = finishedWork.flags; @@ -632,10 +635,12 @@ function commitLayoutEffectOnFiber( componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function abortRootTransitions( @@ -1628,7 +1633,7 @@ function commitMutationEffectsOnFiber( lanes: Lanes, ) { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); const current = finishedWork.alternate; const flags = finishedWork.flags; @@ -2137,10 +2142,12 @@ function commitMutationEffectsOnFiber( componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function commitReconciliationEffects(finishedWork: Fiber) { @@ -2213,7 +2220,7 @@ function recursivelyTraverseLayoutEffects( export function disappearLayoutEffects(finishedWork: Fiber) { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: @@ -2286,10 +2293,12 @@ export function disappearLayoutEffects(finishedWork: Fiber) { componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function recursivelyTraverseDisappearLayoutEffects(parentFiber: Fiber) { @@ -2311,7 +2320,7 @@ export function reappearLayoutEffects( includeWorkInProgressEffects: boolean, ) { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); // Turn on layout effects in a tree that previously disappeared. const flags = finishedWork.flags; switch (finishedWork.tag) { @@ -2462,10 +2471,12 @@ export function reappearLayoutEffects( componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function recursivelyTraverseReappearLayoutEffects( @@ -2702,7 +2713,7 @@ function commitPassiveMountOnFiber( endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ): void { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); // When updating this function, also update reconnectPassiveEffects, which does // most of the same things when an offscreen tree goes from hidden -> visible, // or when toggling effects inside a hidden tree. @@ -3114,10 +3125,12 @@ function commitPassiveMountOnFiber( componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function recursivelyTraverseReconnectPassiveEffects( @@ -3177,7 +3190,7 @@ export function reconnectPassiveEffects( endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ) { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); // If this component rendered in Profiling mode (DEV or in Profiler component) then log its // render time. We do this after the fact in the passive effect to avoid the overhead of this // getting in the way of the render characteristics and avoid the overhead of unwinding @@ -3371,10 +3384,12 @@ export function reconnectPassiveEffects( componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function recursivelyTraverseAtomicPassiveEffects( @@ -3651,7 +3666,7 @@ function recursivelyTraversePassiveUnmountEffects(parentFiber: Fiber): void { function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: @@ -3736,10 +3751,12 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } function recursivelyTraverseDisconnectPassiveEffects(parentFiber: Fiber): void { @@ -3859,7 +3876,7 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber( nearestMountedAncestor: Fiber | null, ): void { const prevEffectStart = pushComponentEffectStart(); - + const prevEffectErrors = pushComponentEffectErrors(); switch (current.tag) { case FunctionComponent: case ForwardRef: @@ -3986,10 +4003,12 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber( componentEffectStartTime, componentEffectEndTime, componentEffectDuration, + componentEffectErrors, ); } popComponentEffectStart(prevEffectStart); + popComponentEffectErrors(prevEffectErrors); } export function invokeLayoutEffectMountInDEV(fiber: Fiber): void { diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index fa78f6cce4a1a..ce599e42a2291 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -207,12 +207,60 @@ export function logComponentErrored( } } +function logComponentEffectErrored( + fiber: Fiber, + startTime: number, + endTime: number, + errors: Array>, +): void { + if (supportsUserTiming) { + const name = getComponentNameFromFiber(fiber); + if (name === null) { + // Skip + return; + } + const properties = []; + if (__DEV__) { + for (let i = 0; i < errors.length; i++) { + const capturedValue = errors[i]; + const error = capturedValue.value; + const message = + typeof error === 'object' && + error !== null && + typeof error.message === 'string' + ? // eslint-disable-next-line react-internal/safe-string-coercion + String(error.message) + : // eslint-disable-next-line react-internal/safe-string-coercion + String(error); + properties.push(['Error', message]); + } + } + performance.measure(name, { + start: startTime, + end: endTime, + detail: { + devtools: { + color: 'error', + track: COMPONENTS_TRACK, + tooltipText: 'A life cycle or effect errored', + properties, + }, + }, + }); + } +} + export function logComponentEffect( fiber: Fiber, startTime: number, endTime: number, selfTime: number, + errors: null | Array>, ): void { + if (errors !== null) { + logComponentEffectErrored(fiber, startTime, endTime, errors); + return; + } const name = getComponentNameFromFiber(fiber); if (name === null) { // Skip diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 2e8b443d22caa..ac136306912c5 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -262,6 +262,7 @@ import { yieldStartTime, yieldReason, startPingTimerByLanes, + recordEffectError, } from './ReactProfilerTimer'; // DEV stuff @@ -3823,6 +3824,9 @@ function captureCommitPhaseErrorOnRoot( error: mixed, ) { const errorInfo = createCapturedValueAtFiber(error, sourceFiber); + if (enableProfilerTimer && enableComponentPerformanceTrack) { + recordEffectError(errorInfo); + } const update = createRootErrorUpdate( rootFiber.stateNode, errorInfo, @@ -3864,6 +3868,9 @@ export function captureCommitPhaseError( !isAlreadyFailedLegacyErrorBoundary(instance)) ) { const errorInfo = createCapturedValueAtFiber(error, sourceFiber); + if (enableProfilerTimer && enableComponentPerformanceTrack) { + recordEffectError(errorInfo); + } const update = createClassErrorUpdate((SyncLane: Lane)); const root = enqueueUpdate(fiber, update, (SyncLane: Lane)); if (root !== null) { diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index d408ba0ff7bd0..7795f627049bb 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -12,6 +12,9 @@ import type {Fiber} from './ReactInternalTypes'; import type {SuspendedReason} from './ReactFiberWorkLoop'; import type {Lane, Lanes} from './ReactFiberLane'; + +import type {CapturedValue} from './ReactCapturedValue'; + import { isTransitionLane, isBlockingLane, @@ -44,6 +47,7 @@ export let profilerEffectDuration: number = -0; export let componentEffectDuration: number = -0; export let componentEffectStartTime: number = -1.1; export let componentEffectEndTime: number = -1.1; +export let componentEffectErrors: null | Array> = null; export let blockingClampTime: number = -0; export let blockingUpdateTime: number = -1.1; // First sync setState scheduled. @@ -270,6 +274,26 @@ export function popComponentEffectStart(prevEffectStart: number): void { } } +export function pushComponentEffectErrors(): null | Array< + CapturedValue, +> { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return null; + } + const prevErrors = componentEffectErrors; + componentEffectErrors = null; + return prevErrors; +} + +export function popComponentEffectErrors( + prevErrors: null | Array>, +): void { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return; + } + componentEffectErrors = prevErrors; +} + /** * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). * @@ -404,6 +428,13 @@ export function recordEffectDuration(fiber: Fiber): void { } } +export function recordEffectError(errorInfo: CapturedValue): void { + if (componentEffectErrors === null) { + componentEffectErrors = []; + } + componentEffectErrors.push(errorInfo); +} + export function startEffectTimer(): void { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return; From 9334142332899c4f9de6aa26d26d2c1f396517af Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 20 Dec 2024 15:12:44 -0500 Subject: [PATCH 4/5] Mark commit phase as errored if there were any errors within --- .../src/ReactFiberPerformanceTrack.js | 54 ++++++++++++++++++- .../src/ReactFiberWorkLoop.js | 11 +++- .../src/ReactProfilerTimer.js | 12 +++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index ce599e42a2291..106316157371a 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -585,7 +585,54 @@ export function logSuspendedCommitPhase( } } -export function logCommitPhase(startTime: number, endTime: number): void { +export function logCommitErrored( + startTime: number, + endTime: number, + errors: Array>, + passive: boolean, +): void { + if (supportsUserTiming) { + const properties = []; + if (__DEV__) { + for (let i = 0; i < errors.length; i++) { + const capturedValue = errors[i]; + const error = capturedValue.value; + const message = + typeof error === 'object' && + error !== null && + typeof error.message === 'string' + ? // eslint-disable-next-line react-internal/safe-string-coercion + String(error.message) + : // eslint-disable-next-line react-internal/safe-string-coercion + String(error); + properties.push(['Error', message]); + } + } + performance.measure('Errored', { + start: startTime, + end: endTime, + detail: { + devtools: { + color: 'error', + track: reusableLaneDevToolDetails.track, + trackGroup: LANES_TRACK_GROUP, + tooltipText: passive ? 'Remaining Effects Errored' : 'Commit Errored', + properties, + }, + }, + }); + } +} + +export function logCommitPhase( + startTime: number, + endTime: number, + errors: null | Array>, +): void { + if (errors !== null) { + logCommitErrored(startTime, endTime, errors, false); + return; + } if (supportsUserTiming) { reusableLaneDevToolDetails.color = 'secondary-dark'; reusableLaneOptions.start = startTime; @@ -613,7 +660,12 @@ export function logPaintYieldPhase( export function logPassiveCommitPhase( startTime: number, endTime: number, + errors: null | Array>, ): void { + if (errors !== null) { + logCommitErrored(startTime, endTime, errors, true); + return; + } if (supportsUserTiming) { reusableLaneDevToolDetails.color = 'secondary-dark'; reusableLaneOptions.start = startTime; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index ac136306912c5..4801aae52468d 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -251,6 +251,7 @@ import { renderStartTime, commitStartTime, commitEndTime, + commitErrors, recordRenderTime, recordCommitTime, recordCommitEndTime, @@ -263,6 +264,7 @@ import { yieldReason, startPingTimerByLanes, recordEffectError, + resetCommitErrors, } from './ReactProfilerTimer'; // DEV stuff @@ -3322,6 +3324,7 @@ function commitRootImpl( if (enableProfilerTimer) { // Mark the current commit time to be shared by all Profilers in this // batch. This enables them to be grouped later. + resetCommitErrors(); recordCommitTime(); if (enableComponentPerformanceTrack) { if (suspendedCommitReason === SUSPENDED_COMMIT) { @@ -3415,6 +3418,7 @@ function commitRootImpl( ? completedRenderEndTime : commitStartTime, commitEndTime, + commitErrors, ); } @@ -3704,6 +3708,7 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) { let passiveEffectStartTime = 0; if (enableProfilerTimer && enableComponentPerformanceTrack) { + resetCommitErrors(); passiveEffectStartTime = now(); logPaintYieldPhase( commitEndTime, @@ -3740,7 +3745,11 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) { if (enableProfilerTimer && enableComponentPerformanceTrack) { const passiveEffectsEndTime = now(); - logPassiveCommitPhase(passiveEffectStartTime, passiveEffectsEndTime); + logPassiveCommitPhase( + passiveEffectStartTime, + passiveEffectsEndTime, + commitErrors, + ); finalizeRender(lanes, passiveEffectsEndTime); } diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index 7795f627049bb..d8e6109a66f3c 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -42,6 +42,7 @@ const {unstable_now: now} = Scheduler; export let renderStartTime: number = -0; export let commitStartTime: number = -0; export let commitEndTime: number = -0; +export let commitErrors: null | Array> = null; export let profilerStartTime: number = -1.1; export let profilerEffectDuration: number = -0; export let componentEffectDuration: number = -0; @@ -429,10 +430,21 @@ export function recordEffectDuration(fiber: Fiber): void { } export function recordEffectError(errorInfo: CapturedValue): void { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return; + } if (componentEffectErrors === null) { componentEffectErrors = []; } componentEffectErrors.push(errorInfo); + if (commitErrors === null) { + commitErrors = []; + } + commitErrors.push(errorInfo); +} + +export function resetCommitErrors(): void { + commitErrors = null; } export function startEffectTimer(): void { From 48f9d0926859fd31880e57532e9d88b7d4e62ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 2 Jan 2025 13:27:56 -0500 Subject: [PATCH 5/5] Life cycle to lifecycle Co-authored-by: Ricky --- packages/react-reconciler/src/ReactFiberPerformanceTrack.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 106316157371a..78d53695a51e1 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -242,7 +242,7 @@ function logComponentEffectErrored( devtools: { color: 'error', track: COMPONENTS_TRACK, - tooltipText: 'A life cycle or effect errored', + tooltipText: 'A lifecycle or effect errored', properties, }, },