250
thenableState: null | ThenableState,
251
isFallback: boolean, // whether this task is rendering inside a fallback tree
252
legacyContext: LegacyContext, // the current legacy context that this task is executing in
253
+ debugTask: null | ConsoleTask, // DEV only
254
// DON'T ANY MORE FIELDS. We at 16 already which otherwise requires converting to a constructor.
255
// Consider splitting into multiple objects or consolidating some fields.
256
};
280
thenableState: null | ThenableState,
281
isFallback: boolean, // whether this task is rendering inside a fallback tree
282
legacyContext: LegacyContext, // the current legacy context that this task is executing in
283
+ debugTask: null | ConsoleTask, // DEV only
284
// DON'T ANY MORE FIELDS. We at 16 already which otherwise requires converting to a constructor.
285
// Consider splitting into multiple objects or consolidating some fields.
286
};
470
null,
471
false,
472
emptyContextObject,
473
+ null,
474
);
475
pingedTasks.push(rootTask);
476
}
613
null,
614
false,
615
emptyContextObject,
616
+ null,
617
);
618
pingedTasks.push(rootTask);
619
return request;
640
null,
641
false,
642
emptyContextObject,
643
+ null,
644
);
645
pingedTasks.push(rootTask);
646
return request;
709
componentStack: null | ComponentStackNode,
710
isFallback: boolean,
711
legacyContext: LegacyContext,
712
+ debugTask: null | ConsoleTask,
713
): RenderTask {
714
request.allPendingTasks++;
715
if (blockedBoundary === null) {
737
if (!disableLegacyContext) {
738
task.legacyContext = legacyContext;
739
}
740
+ if (__DEV__ && enableOwnerStacks) {
741
+ task.debugTask = debugTask;
742
+ }
743
abortSet.add(task);
744
return task;
745
}
760
componentStack: null | ComponentStackNode,
761
isFallback: boolean,
762
legacyContext: LegacyContext,
763
+ debugTask: null | ConsoleTask,
764
): ReplayTask {
765
request.allPendingTasks++;
766
if (blockedBoundary === null) {
789
if (!disableLegacyContext) {
790
task.legacyContext = legacyContext;
791
}
792
+ if (__DEV__ && enableOwnerStacks) {
793
+ task.debugTask = debugTask;
794
+ }
795
abortSet.add(task);
796
return task;
797
}
900
type,
901
};
902
}
890
-function createServerComponentStack(
903
+function pushServerComponentStack(
904
task: Task,
905
debugInfo: void | null | ReactDebugInfo,
893
-): null | ComponentStackNode {
906
+): void {
907
+ if (!__DEV__) {
908
+ // eslint-disable-next-line react-internal/prod-error-codes
909
+ throw new Error(
910
+ 'pushServerComponentStack should never be called in production. This is a bug in React.',
911
+ );
912
+ }
913
// Build a Server Component parent stack from the debugInfo.
895
- if (__DEV__) {
896
- let node = task.componentStack;
897
- if (debugInfo != null) {
898
- const stack: ReactDebugInfo = debugInfo;
899
- for (let i = 0; i < stack.length; i++) {
900
- const componentInfo: ReactComponentInfo = (stack[i]: any);
901
- if (typeof componentInfo.name !== 'string') {
902
- continue;
903
- }
904
- let name = componentInfo.name;
905
- const env = componentInfo.env;
906
- if (env) {
907
- name += ' (' + env + ')';
908
- }
909
- node = {
910
- tag: 3,
911
- parent: node,
912
- type: name,
913
- owner: componentInfo.owner,
914
- stack: componentInfo.stack,
915
- };
914
+ if (debugInfo != null) {
915
+ const stack: ReactDebugInfo = debugInfo;
916
+ for (let i = 0; i < stack.length; i++) {
917
+ const componentInfo: ReactComponentInfo = (stack[i]: any);
918
+ if (typeof componentInfo.name !== 'string') {
919
+ continue;
920
+ }
921
+ if (enableOwnerStacks && componentInfo.stack === undefined) {
922
+ continue;
923
+ }
924
+ let name = componentInfo.name;
925
+ const env = componentInfo.env;
926
+ if (env) {
927
+ name += ' (' + env + ')';
928
+ }
929
+ task.componentStack = {
930
+ tag: 3,
931
+ parent: task.componentStack,
932
+ type: name,
933
+ owner: componentInfo.owner,
934
+ stack: componentInfo.stack,
935
+ };
936
+ if (enableOwnerStacks) {
937
+ task.debugTask = (componentInfo.task: any);
938
}
939
}
918
- return node;
940
}
920
- // eslint-disable-next-line react-internal/prod-error-codes
921
- throw new Error(
922
- 'createServerComponentStack should never be called in production. This is a bug in React.',
923
- );
941
}
942
943
function createComponentStackFromType(
1017
request: Request,
1018
reason: string,
1019
postponeInfo: ThrownInfo,
1020
+ debugTask: null | ConsoleTask,
1021
): void {
1022
// If this callback errors, we intentionally let that error bubble up to become a fatal error
1023
// so that someone fixes the error reporting instead of hiding it.
1006
- request.onPostpone(reason, postponeInfo);
1024
+ const onPostpone = request.onPostpone;
1025
+ if (__DEV__ && enableOwnerStacks && debugTask) {
1026
+ debugTask.run(onPostpone.bind(null, reason, postponeInfo));
1027
+ } else {
1028
+ onPostpone(reason, postponeInfo);
1029
+ }
1030
}
1031
1032
function logRecoverableError(
1033
request: Request,
1034
error: any,
1035
errorInfo: ThrownInfo,
1036
+ debugTask: null | ConsoleTask,
1037
): ?string {
1038
// If this callback errors, we intentionally let that error bubble up to become a fatal error
1039
// so that someone fixes the error reporting instead of hiding it.
1016
- const errorDigest = request.onError(error, errorInfo);
1040
+ const onError = request.onError;
1041
+ const errorDigest =
1042
+ __DEV__ && enableOwnerStacks && debugTask
1043
+ ? debugTask.run(onError.bind(null, error, errorInfo))
1044
+ : onError(error, errorInfo);
1045
if (errorDigest != null && typeof errorDigest !== 'string') {
1046
// We used to throw here but since this gets called from a variety of unprotected places it
1047
// seems better to just warn and discard the returned value.
1056
return errorDigest;
1057
}
1058
1031
-function fatalError(request: Request, error: mixed): void {
1059
+function fatalError(
1060
+ request: Request,
1061
+ error: mixed,
1062
+ errorInfo: ThrownInfo,
1063
+ debugTask: null | ConsoleTask,
1064
+): void {
1065
// This is called outside error handling code such as if the root errors outside
1066
// a suspense boundary or if the root suspense boundary's fallback errors.
1067
// It's also called if React itself or its host configs errors.
1068
const onShellError = request.onShellError;
1036
- onShellError(error);
1069
const onFatalError = request.onFatalError;
1038
- onFatalError(error);
1070
+ if (__DEV__ && enableOwnerStacks && debugTask) {
1071
+ debugTask.run(onShellError.bind(null, error));
1072
+ debugTask.run(onFatalError.bind(null, error));
1073
+ } else {
1074
+ onShellError(error);
1075
+ onFatalError(error);
1076
+ }
1077
if (request.destination !== null) {
1078
request.status = CLOSED;
1079
closeWithError(request.destination, error);
1206
error.$$typeof === REACT_POSTPONE_TYPE
1207
) {
1208
const postponeInstance: Postpone = (error: any);
1171
- logPostpone(request, postponeInstance.message, thrownInfo);
1209
+ logPostpone(
1210
+ request,
1211
+ postponeInstance.message,
1212
+ thrownInfo,
1213
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
1214
+ );
1215
// TODO: Figure out a better signal than a magic digest value.
1216
errorDigest = 'POSTPONE';
1217
} else {
1175
- errorDigest = logRecoverableError(request, error, thrownInfo);
1218
+ errorDigest = logRecoverableError(
1219
+ request,
1220
+ error,
1221
+ thrownInfo,
1222
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
1223
+ );
1224
}
1225
encodeErrorForBoundary(newBoundary, errorDigest, error, thrownInfo, false);
1226
1279
suspenseComponentStack,
1280
true,
1281
!disableLegacyContext ? task.legacyContext : emptyContextObject,
1282
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
1283
);
1284
// TODO: This should be queued at a separate lower priority queue so that we only work
1285
// on preparing fallbacks if we don't have any more main content to task on.
1363
error.$$typeof === REACT_POSTPONE_TYPE
1364
) {
1365
const postponeInstance: Postpone = (error: any);
1317
- logPostpone(request, postponeInstance.message, thrownInfo);
1366
+ logPostpone(
1367
+ request,
1368
+ postponeInstance.message,
1369
+ thrownInfo,
1370
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
1371
+ );
1372
// TODO: Figure out a better signal than a magic digest value.
1373
errorDigest = 'POSTPONE';
1374
} else {
1321
- errorDigest = logRecoverableError(request, error, thrownInfo);
1375
+ errorDigest = logRecoverableError(
1376
+ request,
1377
+ error,
1378
+ thrownInfo,
1379
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
1380
+ );
1381
}
1382
encodeErrorForBoundary(
1383
resumedBoundary,
1430
suspenseComponentStack,
1431
true,
1432
!disableLegacyContext ? task.legacyContext : emptyContextObject,
1433
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
1434
);
1435
// TODO: This should be queued at a separate lower priority queue so that we only work
1436
// on preparing fallbacks if we don't have any more main content to task on.
2438
thrownInfo,
2439
childNodes,
2440
childSlots,
2441
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
2442
);
2443
}
2444
task.replay = replay;
2631
const owner = __DEV__ ? element._owner : null;
2632
const stack = __DEV__ && enableOwnerStacks ? element._debugStack : null;
2633
2634
+ let previousDebugTask: null | ConsoleTask = null;
2635
const previousComponentStack = task.componentStack;
2636
+ let debugTask: null | ConsoleTask;
2637
if (__DEV__) {
2575
- task.componentStack = createServerComponentStack(
2576
- task,
2577
- element._debugInfo,
2578
- );
2638
+ if (enableOwnerStacks) {
2639
+ previousDebugTask = task.debugTask;
2640
+ }
2641
+ pushServerComponentStack(task, element._debugInfo);
2642
+ if (enableOwnerStacks) {
2643
+ task.debugTask = debugTask = element._debugTask;
2644
+ }
2645
}
2646
2647
const name = getComponentNameFromType(type);
2649
key == null ? (childIndex === -1 ? 0 : childIndex) : key;
2650
const keyPath = [task.keyPath, name, keyOrIndex];
2651
if (task.replay !== null) {
2586
- const debugTask: null | ConsoleTask =
2587
- __DEV__ && enableOwnerStacks ? element._debugTask : null;
2652
if (debugTask) {
2653
debugTask.run(
2654
replayElement.bind(
2687
// prelude and skip it during the replay.
2688
} else {
2689
// We're doing a plain render.
2626
- const debugTask: null | ConsoleTask =
2627
- __DEV__ && enableOwnerStacks ? element._debugTask : null;
2690
if (debugTask) {
2691
debugTask.run(
2692
renderElement.bind(
2716
}
2717
if (__DEV__) {
2718
task.componentStack = previousComponentStack;
2719
+ if (enableOwnerStacks) {
2720
+ task.debugTask = previousDebugTask;
2721
+ }
2722
}
2723
return;
2724
}
2730
case REACT_LAZY_TYPE: {
2731
const lazyNode: LazyComponentType<any, any> = (node: any);
2732
const previousComponentStack = task.componentStack;
2733
+ let previousDebugTask = null;
2734
if (__DEV__) {
2669
- task.componentStack = createServerComponentStack(
2670
- task,
2671
- lazyNode._debugInfo,
2672
- );
2735
+ if (enableOwnerStacks) {
2736
+ previousDebugTask = task.debugTask;
2737
+ }
2738
+ pushServerComponentStack(task, lazyNode._debugInfo);
2739
}
2740
if (!__DEV__ || task.componentStack === previousComponentStack) {
2741
// TODO: Do we really need this stack frame? We don't on the client.
2758
// We restore the stack before rendering the resolved node because once the Lazy
2759
// has resolved any future errors
2760
task.componentStack = previousComponentStack;
2761
+ if (__DEV__ && enableOwnerStacks) {
2762
+ task.debugTask = previousDebugTask;
2763
+ }
2764
2765
// Now we render the resolved node
2766
renderNodeDestructive(request, task, resolvedNode, childIndex);
2881
const thenable: Thenable<ReactNodeList> = (maybeUsable: any);
2882
const previousComponentStack = task.componentStack;
2883
if (__DEV__) {
2815
- task.componentStack = createServerComponentStack(
2816
- task,
2817
- thenable._debugInfo,
2818
- );
2884
+ pushServerComponentStack(task, thenable._debugInfo);
2885
}
2886
const result = renderNodeDestructive(
2887
request,
3013
thrownInfo,
3014
childNodes,
3015
childSlots,
3016
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
3017
);
3018
}
3019
task.replay = replay;
3125
): void {
3126
const prevKeyPath = task.keyPath;
3127
const previousComponentStack = task.componentStack;
3128
+ let previousDebugTask = null;
3129
if (__DEV__) {
3130
+ if (enableOwnerStacks) {
3131
+ previousDebugTask = task.debugTask;
3132
+ }
3133
// We read debugInfo from task.node instead of children because it might have been an
3134
// unwrapped iterable so we read from the original node.
3064
- task.componentStack = createServerComponentStack(
3065
- task,
3066
- (task.node: any)._debugInfo,
3067
- );
3135
+ pushServerComponentStack(task, (task.node: any)._debugInfo);
3136
}
3137
if (childIndex !== -1) {
3138
task.keyPath = [task.keyPath, 'Fragment', childIndex];
3147
task.keyPath = prevKeyPath;
3148
if (__DEV__) {
3149
task.componentStack = previousComponentStack;
3150
+ if (enableOwnerStacks) {
3151
+ task.debugTask = previousDebugTask;
3152
+ }
3153
}
3154
return;
3155
}
3183
task.keyPath = prevKeyPath;
3184
if (__DEV__) {
3185
task.componentStack = previousComponentStack;
3186
+ if (enableOwnerStacks) {
3187
+ task.debugTask = previousDebugTask;
3188
+ }
3189
}
3190
return;
3191
}
3208
task.keyPath = prevKeyPath;
3209
if (__DEV__) {
3210
task.componentStack = previousComponentStack;
3211
+ if (enableOwnerStacks) {
3212
+ task.debugTask = previousDebugTask;
3213
+ }
3214
}
3215
}
3216
3404
reason: string,
3405
thrownInfo: ThrownInfo,
3406
): Segment {
3330
- logPostpone(request, reason, thrownInfo);
3407
+ logPostpone(
3408
+ request,
3409
+ reason,
3410
+ thrownInfo,
3411
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
3412
+ );
3413
// Something suspended, we'll need to create a new segment and resolve it later.
3414
const segment = task.blockedSegment;
3415
const insertionIndex = segment.chunks.length;
3453
task.componentStack !== null ? task.componentStack.parent : null,
3454
task.isFallback,
3455
!disableLegacyContext ? task.legacyContext : emptyContextObject,
3456
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
3457
);
3458
3459
const ping = newTask.ping;
3500
task.componentStack !== null ? task.componentStack.parent : null,
3501
task.isFallback,
3502
!disableLegacyContext ? task.legacyContext : emptyContextObject,
3503
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
3504
);
3505
3506
const ping = newTask.ping;
3693
errorInfo: ThrownInfo,
3694
replayNodes: ReplayNode[],
3695
resumeSlots: ResumeSlots,
3696
+ debugTask: null | ConsoleTask,
3697
): void {
3698
// Erroring during a replay doesn't actually cause an error by itself because
3699
// that component has already rendered. What causes the error is the resumable
3710
error.$$typeof === REACT_POSTPONE_TYPE
3711
) {
3712
const postponeInstance: Postpone = (error: any);
3628
- logPostpone(request, postponeInstance.message, errorInfo);
3713
+ logPostpone(request, postponeInstance.message, errorInfo, debugTask);
3714
// TODO: Figure out a better signal than a magic digest value.
3715
errorDigest = 'POSTPONE';
3716
} else {
3632
- errorDigest = logRecoverableError(request, error, errorInfo);
3717
+ errorDigest = logRecoverableError(request, error, errorInfo, debugTask);
3718
}
3719
abortRemainingReplayNodes(
3720
request,
3733
boundary: Root | SuspenseBoundary,
3734
error: mixed,
3735
errorInfo: ThrownInfo,
3736
+ debugTask: null | ConsoleTask,
3737
) {
3738
// Report the error to a global handler.
3739
let errorDigest;
3744
error.$$typeof === REACT_POSTPONE_TYPE
3745
) {
3746
const postponeInstance: Postpone = (error: any);
3661
- logPostpone(request, postponeInstance.message, errorInfo);
3747
+ logPostpone(request, postponeInstance.message, errorInfo, debugTask);
3748
// TODO: Figure out a better signal than a magic digest value.
3749
errorDigest = 'POSTPONE';
3750
} else {
3665
- errorDigest = logRecoverableError(request, error, errorInfo);
3751
+ errorDigest = logRecoverableError(request, error, errorInfo, debugTask);
3752
}
3753
if (boundary === null) {
3668
- fatalError(request, error);
3754
+ fatalError(request, error, errorInfo, debugTask);
3755
} else {
3756
boundary.pendingTasks--;
3757
if (boundary.status !== CLIENT_RENDERED) {
3907
'The render was aborted with postpone when the shell is incomplete. Reason: ' +
3908
postponeInstance.message,
3909
);
3824
- logRecoverableError(request, fatal, errorInfo);
3825
- fatalError(request, fatal);
3910
+ logRecoverableError(request, fatal, errorInfo, null);
3911
+ fatalError(request, fatal, errorInfo, null);
3912
} else {
3827
- logRecoverableError(request, error, errorInfo);
3828
- fatalError(request, error);
3913
+ logRecoverableError(request, error, errorInfo, null);
3914
+ fatalError(request, error, errorInfo, null);
3915
}
3916
return;
3917
} else {
3928
error.$$typeof === REACT_POSTPONE_TYPE
3929
) {
3930
const postponeInstance: Postpone = (error: any);
3845
- logPostpone(request, postponeInstance.message, errorInfo);
3931
+ logPostpone(request, postponeInstance.message, errorInfo, null);
3932
// TODO: Figure out a better signal than a magic digest value.
3933
errorDigest = 'POSTPONE';
3934
} else {
3849
- errorDigest = logRecoverableError(request, error, errorInfo);
3935
+ errorDigest = logRecoverableError(request, error, errorInfo, null);
3936
}
3937
abortRemainingReplayNodes(
3938
request,
3966
error.$$typeof === REACT_POSTPONE_TYPE
3967
) {
3968
const postponeInstance: Postpone = (error: any);
3883
- logPostpone(request, postponeInstance.message, errorInfo);
3969
+ logPostpone(request, postponeInstance.message, errorInfo, null);
3970
// TODO: Figure out a better signal than a magic digest value.
3971
errorDigest = 'POSTPONE';
3972
} else {
3887
- errorDigest = logRecoverableError(request, error, errorInfo);
3973
+ errorDigest = logRecoverableError(request, error, errorInfo, null);
3974
}
3975
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, true);
3976
4008
} catch (error) {
4009
// We assume preloads are optimistic and thus non-fatal if errored.
4010
const errorInfo: ThrownInfo = {};
3925
- logRecoverableError(request, error, errorInfo);
4011
+ logRecoverableError(request, error, errorInfo, null);
4012
}
4013
}
4014
4250
const postponeInstance: Postpone = (x: any);
4251
4252
const postponeInfo = getThrownInfo(task.componentStack);
4167
- logPostpone(request, postponeInstance.message, postponeInfo);
4253
+ logPostpone(
4254
+ request,
4255
+ postponeInstance.message,
4256
+ postponeInfo,
4257
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
4258
+ );
4259
trackPostpone(request, trackedPostpones, task, segment);
4260
finishedTask(request, task.blockedBoundary, segment);
4261
return;
4265
const errorInfo = getThrownInfo(task.componentStack);
4266
task.abortSet.delete(task);
4267
segment.status = ERRORED;
4177
- erroredTask(request, task.blockedBoundary, x, errorInfo);
4268
+ erroredTask(
4269
+ request,
4270
+ task.blockedBoundary,
4271
+ x,
4272
+ errorInfo,
4273
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
4274
+ );
4275
return;
4276
} finally {
4277
if (__DEV__) {
4350
errorInfo,
4351
task.replay.nodes,
4352
task.replay.slots,
4353
+ __DEV__ && enableOwnerStacks ? task.debugTask : null,
4354
);
4355
request.pendingRootTasks--;
4356
if (request.pendingRootTasks === 0) {
4404
}
4405
} catch (error) {
4406
const errorInfo: ThrownInfo = {};
4309
- logRecoverableError(request, error, errorInfo);
4310
- fatalError(request, error);
4407
+ logRecoverableError(request, error, errorInfo, null);
4408
+ fatalError(request, error, errorInfo, null);
4409
} finally {
4410
setCurrentResumableState(prevResumableState);
4411
ReactSharedInternals.H = prevDispatcher;
4989
flushCompletedQueues(request, destination);
4990
} catch (error) {
4991
const errorInfo: ThrownInfo = {};
4894
- logRecoverableError(request, error, errorInfo);
4895
- fatalError(request, error);
4992
+ logRecoverableError(request, error, errorInfo, null);
4993
+ fatalError(request, error, errorInfo, null);
4994
}
4995
}
4996
5015
}
5016
} catch (error) {
5017
const errorInfo: ThrownInfo = {};
4920
- logRecoverableError(request, error, errorInfo);
4921
- fatalError(request, error);
5018
+ logRecoverableError(request, error, errorInfo, null);
5019
+ fatalError(request, error, errorInfo, null);
5020
}
5021
}
5022