Skip to content

Commit f972645

Browse files
committed
Include a component stack in prod but only lazily generate it
1 parent 2e72ea8 commit f972645

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
@@ -856,27 +856,23 @@ type ThrownInfo = {
856856
export type ErrorInfo = ThrownInfo;
857857
export type PostponeInfo = ThrownInfo;
858858

859-
// While we track component stacks in prod all the time we only produce a reified stack in dev and
860-
// during prerender in Prod. The reason for this is that the stack is useful for prerender where the timeliness
861-
// of the request is less critical than the observability of the execution. For renders and resumes however we
862-
// prioritize speed of the request.
863-
function getThrownInfo(
864-
request: Request,
865-
node: null | ComponentStackNode,
866-
): ThrownInfo {
867-
if (
868-
node &&
869-
// Always produce a stack in dev
870-
(__DEV__ ||
871-
// Produce a stack in prod if we're in a prerender
872-
request.trackedPostpones !== null)
873-
) {
874-
return {
875-
componentStack: getStackFromNode(node),
876-
};
877-
} else {
878-
return {};
859+
function getThrownInfo(node: null | ComponentStackNode): ThrownInfo {
860+
const errorInfo: ThrownInfo = {};
861+
if (node) {
862+
Object.defineProperty(errorInfo, 'componentStack', {
863+
configurable: true,
864+
enumerable: true,
865+
get() {
866+
// Lazyily generate the stack since it's expensive.
867+
const stack = getStackFromNode(node);
868+
Object.defineProperty(errorInfo, 'componentStack', {
869+
value: stack,
870+
});
871+
return stack;
872+
},
873+
});
879874
}
875+
return errorInfo;
880876
}
881877

882878
function encodeErrorForBoundary(
@@ -1073,7 +1069,7 @@ function renderSuspenseBoundary(
10731069
} catch (error: mixed) {
10741070
contentRootSegment.status = ERRORED;
10751071
newBoundary.status = CLIENT_RENDERED;
1076-
const thrownInfo = getThrownInfo(request, task.componentStack);
1072+
const thrownInfo = getThrownInfo(task.componentStack);
10771073
let errorDigest;
10781074
if (
10791075
enablePostpone &&
@@ -1217,7 +1213,7 @@ function replaySuspenseBoundary(
12171213
}
12181214
} catch (error: mixed) {
12191215
resumedBoundary.status = CLIENT_RENDERED;
1220-
const thrownInfo = getThrownInfo(request, task.componentStack);
1216+
const thrownInfo = getThrownInfo(task.componentStack);
12211217
let errorDigest;
12221218
if (
12231219
enablePostpone &&
@@ -2172,7 +2168,7 @@ function replayElement(
21722168
// in the original prerender. What's unable to complete is the child
21732169
// replay nodes which might be Suspense boundaries which are able to
21742170
// absorb the error and we can still continue with siblings.
2175-
const thrownInfo = getThrownInfo(request, task.componentStack);
2171+
const thrownInfo = getThrownInfo(task.componentStack);
21762172
erroredReplay(
21772173
request,
21782174
task.blockedBoundary,
@@ -2642,7 +2638,7 @@ function replayFragment(
26422638
// replay nodes which might be Suspense boundaries which are able to
26432639
// absorb the error and we can still continue with siblings.
26442640
// This is an error, stash the component stack if it is null.
2645-
const thrownInfo = getThrownInfo(request, task.componentStack);
2641+
const thrownInfo = getThrownInfo(task.componentStack);
26462642
erroredReplay(
26472643
request,
26482644
task.blockedBoundary,
@@ -3195,7 +3191,7 @@ function renderNode(
31953191
const trackedPostpones = request.trackedPostpones;
31963192

31973193
const postponeInstance: Postpone = (x: any);
3198-
const thrownInfo = getThrownInfo(request, task.componentStack);
3194+
const thrownInfo = getThrownInfo(task.componentStack);
31993195
const postponedSegment = injectPostponedHole(
32003196
request,
32013197
((task: any): RenderTask), // We don't use ReplayTasks in prerenders.
@@ -3506,7 +3502,7 @@ function abortTask(task: Task, request: Request, error: mixed): void {
35063502
boundary.status = CLIENT_RENDERED;
35073503
// We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which
35083504
// boundary the message is referring to
3509-
const errorInfo = getThrownInfo(request, task.componentStack);
3505+
const errorInfo = getThrownInfo(task.componentStack);
35103506
let errorDigest;
35113507
if (
35123508
enablePostpone &&
@@ -3798,15 +3794,15 @@ function retryRenderTask(
37983794
task.abortSet.delete(task);
37993795
const postponeInstance: Postpone = (x: any);
38003796

3801-
const postponeInfo = getThrownInfo(request, task.componentStack);
3797+
const postponeInfo = getThrownInfo(task.componentStack);
38023798
logPostpone(request, postponeInstance.message, postponeInfo);
38033799
trackPostpone(request, trackedPostpones, task, segment);
38043800
finishedTask(request, task.blockedBoundary, segment);
38053801
return;
38063802
}
38073803
}
38083804

3809-
const errorInfo = getThrownInfo(request, task.componentStack);
3805+
const errorInfo = getThrownInfo(task.componentStack);
38103806
task.abortSet.delete(task);
38113807
segment.status = ERRORED;
38123808
erroredTask(request, task.blockedBoundary, x, errorInfo);
@@ -3880,7 +3876,7 @@ function retryReplayTask(request: Request, task: ReplayTask): void {
38803876
}
38813877
task.replay.pendingTasks--;
38823878
task.abortSet.delete(task);
3883-
const errorInfo = getThrownInfo(request, task.componentStack);
3879+
const errorInfo = getThrownInfo(task.componentStack);
38843880
erroredReplay(
38853881
request,
38863882
task.blockedBoundary,

0 commit comments

Comments
 (0)