Skip to content

Commit 50f00fd

Browse files
authored
[Flight] Mark Errored Server Components (facebook#31879)
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.
1 parent d4ac768 commit 50f00fd

File tree

2 files changed

+73
-8
lines changed

2 files changed

+73
-8
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import {
7373
markAllTracksInOrder,
7474
logComponentRender,
7575
logDedupedComponentRender,
76+
logComponentErrored,
7677
} from './ReactFlightPerformanceTrack';
7778

7879
import {
@@ -2876,6 +2877,7 @@ function flushComponentPerformance(
28762877

28772878
if (debugInfo) {
28782879
let endTime = 0;
2880+
let isLastComponent = true;
28792881
for (let i = debugInfo.length - 1; i >= 0; i--) {
28802882
const info = debugInfo[i];
28812883
if (typeof info.time === 'number') {
@@ -2890,17 +2892,37 @@ function flushComponentPerformance(
28902892
const startTimeInfo = debugInfo[i - 1];
28912893
if (typeof startTimeInfo.time === 'number') {
28922894
const startTime = startTimeInfo.time;
2893-
logComponentRender(
2894-
componentInfo,
2895-
trackIdx,
2896-
startTime,
2897-
endTime,
2898-
childrenEndTime,
2899-
response._rootEnvironmentName,
2900-
);
2895+
if (
2896+
isLastComponent &&
2897+
root.status === ERRORED &&
2898+
root.reason !== response._closedReason
2899+
) {
2900+
// If this is the last component to render before this chunk rejected, then conceptually
2901+
// this component errored. If this was a cancellation then it wasn't this component that
2902+
// errored.
2903+
logComponentErrored(
2904+
componentInfo,
2905+
trackIdx,
2906+
startTime,
2907+
endTime,
2908+
childrenEndTime,
2909+
response._rootEnvironmentName,
2910+
root.reason,
2911+
);
2912+
} else {
2913+
logComponentRender(
2914+
componentInfo,
2915+
trackIdx,
2916+
startTime,
2917+
endTime,
2918+
childrenEndTime,
2919+
response._rootEnvironmentName,
2920+
);
2921+
}
29012922
// Track the root most component of the result for deduping logging.
29022923
result.component = componentInfo;
29032924
}
2925+
isLastComponent = false;
29042926
}
29052927
}
29062928
}

packages/react-client/src/ReactFlightPerformanceTrack.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,49 @@ export function logComponentRender(
102102
}
103103
}
104104

105+
export function logComponentErrored(
106+
componentInfo: ReactComponentInfo,
107+
trackIdx: number,
108+
startTime: number,
109+
endTime: number,
110+
childrenEndTime: number,
111+
rootEnv: string,
112+
error: mixed,
113+
): void {
114+
if (supportsUserTiming) {
115+
const properties = [];
116+
if (__DEV__) {
117+
const message =
118+
typeof error === 'object' &&
119+
error !== null &&
120+
typeof error.message === 'string'
121+
? // eslint-disable-next-line react-internal/safe-string-coercion
122+
String(error.message)
123+
: // eslint-disable-next-line react-internal/safe-string-coercion
124+
String(error);
125+
properties.push(['Error', message]);
126+
}
127+
const env = componentInfo.env;
128+
const name = componentInfo.name;
129+
const isPrimaryEnv = env === rootEnv;
130+
const entryName =
131+
isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']';
132+
performance.measure(entryName, {
133+
start: startTime < 0 ? 0 : startTime,
134+
end: childrenEndTime,
135+
detail: {
136+
devtools: {
137+
color: 'error',
138+
track: trackNames[trackIdx],
139+
trackGroup: COMPONENTS_TRACK,
140+
tooltipText: entryName + ' Errored',
141+
properties,
142+
},
143+
},
144+
});
145+
}
146+
}
147+
105148
export function logDedupedComponentRender(
106149
componentInfo: ReactComponentInfo,
107150
trackIdx: number,

0 commit comments

Comments
 (0)