Skip to content

Commit 476f6d0

Browse files
committed
Include a component stack in prod but only lazily generate it
1 parent 100dfd7 commit 476f6d0

File tree

1 file changed

+25
-29
lines changed

1 file changed

+25
-29
lines changed

packages/react-server/src/ReactFizzServer.js

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -904,27 +904,23 @@ type ThrownInfo = {
904904
export type ErrorInfo = ThrownInfo;
905905
export type PostponeInfo = ThrownInfo;
906906

907-
// While we track component stacks in prod all the time we only produce a reified stack in dev and
908-
// during prerender in Prod. The reason for this is that the stack is useful for prerender where the timeliness
909-
// of the request is less critical than the observability of the execution. For renders and resumes however we
910-
// prioritize speed of the request.
911-
function getThrownInfo(
912-
request: Request,
913-
node: null | ComponentStackNode,
914-
): ThrownInfo {
915-
if (
916-
node &&
917-
// Always produce a stack in dev
918-
(__DEV__ ||
919-
// Produce a stack in prod if we're in a prerender
920-
request.trackedPostpones !== null)
921-
) {
922-
return {
923-
componentStack: getStackFromNode(node),
924-
};
925-
} else {
926-
return {};
907+
function getThrownInfo(node: null | ComponentStackNode): ThrownInfo {
908+
const errorInfo: ThrownInfo = {};
909+
if (node) {
910+
Object.defineProperty(errorInfo, 'componentStack', {
911+
configurable: true,
912+
enumerable: true,
913+
get() {
914+
// Lazyily generate the stack since it's expensive.
915+
const stack = getStackFromNode(node);
916+
Object.defineProperty(errorInfo, 'componentStack', {
917+
value: stack,
918+
});
919+
return stack;
920+
},
921+
});
927922
}
923+
return errorInfo;
928924
}
929925

930926
function encodeErrorForBoundary(
@@ -1123,7 +1119,7 @@ function renderSuspenseBoundary(
11231119
} catch (error: mixed) {
11241120
contentRootSegment.status = ERRORED;
11251121
newBoundary.status = CLIENT_RENDERED;
1126-
const thrownInfo = getThrownInfo(request, task.componentStack);
1122+
const thrownInfo = getThrownInfo(task.componentStack);
11271123
let errorDigest;
11281124
if (
11291125
enablePostpone &&
@@ -1269,7 +1265,7 @@ function replaySuspenseBoundary(
12691265
}
12701266
} catch (error: mixed) {
12711267
resumedBoundary.status = CLIENT_RENDERED;
1272-
const thrownInfo = getThrownInfo(request, task.componentStack);
1268+
const thrownInfo = getThrownInfo(task.componentStack);
12731269
let errorDigest;
12741270
if (
12751271
enablePostpone &&
@@ -2333,7 +2329,7 @@ function replayElement(
23332329
// in the original prerender. What's unable to complete is the child
23342330
// replay nodes which might be Suspense boundaries which are able to
23352331
// absorb the error and we can still continue with siblings.
2336-
const thrownInfo = getThrownInfo(request, task.componentStack);
2332+
const thrownInfo = getThrownInfo(task.componentStack);
23372333
erroredReplay(
23382334
request,
23392335
task.blockedBoundary,
@@ -2864,7 +2860,7 @@ function replayFragment(
28642860
// replay nodes which might be Suspense boundaries which are able to
28652861
// absorb the error and we can still continue with siblings.
28662862
// This is an error, stash the component stack if it is null.
2867-
const thrownInfo = getThrownInfo(request, task.componentStack);
2863+
const thrownInfo = getThrownInfo(task.componentStack);
28682864
erroredReplay(
28692865
request,
28702866
task.blockedBoundary,
@@ -3457,7 +3453,7 @@ function renderNode(
34573453
const trackedPostpones = request.trackedPostpones;
34583454

34593455
const postponeInstance: Postpone = (x: any);
3460-
const thrownInfo = getThrownInfo(request, task.componentStack);
3456+
const thrownInfo = getThrownInfo(task.componentStack);
34613457
const postponedSegment = injectPostponedHole(
34623458
request,
34633459
((task: any): RenderTask), // We don't use ReplayTasks in prerenders.
@@ -3768,7 +3764,7 @@ function abortTask(task: Task, request: Request, error: mixed): void {
37683764
boundary.status = CLIENT_RENDERED;
37693765
// We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which
37703766
// boundary the message is referring to
3771-
const errorInfo = getThrownInfo(request, task.componentStack);
3767+
const errorInfo = getThrownInfo(task.componentStack);
37723768
let errorDigest;
37733769
if (
37743770
enablePostpone &&
@@ -4060,15 +4056,15 @@ function retryRenderTask(
40604056
task.abortSet.delete(task);
40614057
const postponeInstance: Postpone = (x: any);
40624058

4063-
const postponeInfo = getThrownInfo(request, task.componentStack);
4059+
const postponeInfo = getThrownInfo(task.componentStack);
40644060
logPostpone(request, postponeInstance.message, postponeInfo);
40654061
trackPostpone(request, trackedPostpones, task, segment);
40664062
finishedTask(request, task.blockedBoundary, segment);
40674063
return;
40684064
}
40694065
}
40704066

4071-
const errorInfo = getThrownInfo(request, task.componentStack);
4067+
const errorInfo = getThrownInfo(task.componentStack);
40724068
task.abortSet.delete(task);
40734069
segment.status = ERRORED;
40744070
erroredTask(request, task.blockedBoundary, x, errorInfo);
@@ -4142,7 +4138,7 @@ function retryReplayTask(request: Request, task: ReplayTask): void {
41424138
}
41434139
task.replay.pendingTasks--;
41444140
task.abortSet.delete(task);
4145-
const errorInfo = getThrownInfo(request, task.componentStack);
4141+
const errorInfo = getThrownInfo(task.componentStack);
41464142
erroredReplay(
41474143
request,
41484144
task.blockedBoundary,

0 commit comments

Comments
 (0)