Skip to content

Commit

Permalink
[Flight] Mark Errored Server Components (facebook#31879)
Browse files Browse the repository at this point in the history
This is similar to facebook#31876 but for Server Components.

It marks them as errored and puts the error message in the Summary
properties.

<img width="1511" alt="Screenshot 2024-12-20 at 5 05 35 PM"
src="https://github.com/user-attachments/assets/92f11e42-0e23-41c7-bfd4-09effb25e024"
/>

This only looks at the current chunk for rejections. That means that
there might still be promises deeper that rejected but it's only the
immediate return value of the Server Component that's considered a
rejection of the component itself.
  • Loading branch information
sebmarkbage authored Dec 28, 2024
1 parent d4ac768 commit 50f00fd
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 8 deletions.
38 changes: 30 additions & 8 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import {
markAllTracksInOrder,
logComponentRender,
logDedupedComponentRender,
logComponentErrored,
} from './ReactFlightPerformanceTrack';

import {
Expand Down Expand Up @@ -2876,6 +2877,7 @@ function flushComponentPerformance(

if (debugInfo) {
let endTime = 0;
let isLastComponent = true;
for (let i = debugInfo.length - 1; i >= 0; i--) {
const info = debugInfo[i];
if (typeof info.time === 'number') {
Expand All @@ -2890,17 +2892,37 @@ function flushComponentPerformance(
const startTimeInfo = debugInfo[i - 1];
if (typeof startTimeInfo.time === 'number') {
const startTime = startTimeInfo.time;
logComponentRender(
componentInfo,
trackIdx,
startTime,
endTime,
childrenEndTime,
response._rootEnvironmentName,
);
if (
isLastComponent &&
root.status === ERRORED &&
root.reason !== response._closedReason
) {
// If this is the last component to render before this chunk rejected, then conceptually
// this component errored. If this was a cancellation then it wasn't this component that
// errored.
logComponentErrored(
componentInfo,
trackIdx,
startTime,
endTime,
childrenEndTime,
response._rootEnvironmentName,
root.reason,
);
} else {
logComponentRender(
componentInfo,
trackIdx,
startTime,
endTime,
childrenEndTime,
response._rootEnvironmentName,
);
}
// Track the root most component of the result for deduping logging.
result.component = componentInfo;
}
isLastComponent = false;
}
}
}
Expand Down
43 changes: 43 additions & 0 deletions packages/react-client/src/ReactFlightPerformanceTrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,49 @@ export function logComponentRender(
}
}

export function logComponentErrored(
componentInfo: ReactComponentInfo,
trackIdx: number,
startTime: number,
endTime: number,
childrenEndTime: number,
rootEnv: string,
error: mixed,
): void {
if (supportsUserTiming) {
const properties = [];
if (__DEV__) {
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]);
}
const env = componentInfo.env;
const name = componentInfo.name;
const isPrimaryEnv = env === rootEnv;
const entryName =
isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']';
performance.measure(entryName, {
start: startTime < 0 ? 0 : startTime,
end: childrenEndTime,
detail: {
devtools: {
color: 'error',
track: trackNames[trackIdx],
trackGroup: COMPONENTS_TRACK,
tooltipText: entryName + ' Errored',
properties,
},
},
});
}
}

export function logDedupedComponentRender(
componentInfo: ReactComponentInfo,
trackIdx: number,
Expand Down

0 comments on commit 50f00fd

Please sign in to comment.