Skip to content

Commit bde36f5

Browse files
committedMay 23, 2024·
Set the current fiber to the source of the error during error reporting (#29044)
This lets us expose the component stack to the error reporting that happens here as `console.error` patching. Now if you just call `console.error` in the error handlers it'll get the component stack added to the end by React DevTools. However, unfortunately this happens a little too late so the Fiber will be disconnected with its `.return` pointer set to null already. So it'll be too late to extract a parent component stack from but you can at least get the stack from source to error boundary. To work around this I manually add the parent component stack in our default handlers when owner stacks are off. We could potentially fix this but you can also just include it yourself if you're calling `console.error` and it's not a problem for owner stacks. This is not a problem for owner stacks because we'll still have those and so for those just calling `console.error` just works. However, the main feature is that by letting React add them, we can switch to using native error stacks when available. DiffTrain build for commit 2e540e2.
1 parent 11e6f25 commit bde36f5

File tree

7 files changed

+236
-83
lines changed

7 files changed

+236
-83
lines changed
 

‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-test-renderer/cjs/ReactTestRenderer-dev.js

+59-18
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<7ba027f268ac025f6f9101e98d1ea585>>
10+
* @generated SignedSource<<98724556db7e01bfefca7439ac7adfc3>>
1111
*/
1212

1313
'use strict';
@@ -54,23 +54,33 @@ function printWarning(level, format, args) {
5454
// When changing this logic, you might want to also
5555
// update consoleWithStackDev.www.js as well.
5656
{
57+
var isErrorLogger = format === '%s\n\n%s\n' || format === '%o\n\n%s\n\n%s\n';
5758
var stack = ReactSharedInternals.getStackAddendum();
5859

5960
if (stack !== '') {
6061
format += '%s';
6162
args = args.concat([stack]);
62-
} // eslint-disable-next-line react-internal/safe-string-coercion
63-
64-
65-
var argsWithFormat = args.map(function (item) {
66-
return String(item);
67-
}); // Careful: RN currently depends on this prefix
63+
}
6864

69-
argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it
65+
if (isErrorLogger) {
66+
// Don't prefix our default logging formatting in ReactFiberErrorLoggger.
67+
// Don't toString the arguments.
68+
args.unshift(format);
69+
} else {
70+
// TODO: Remove this prefix and stop toStringing in the wrapper and
71+
// instead do it at each callsite as needed.
72+
// Careful: RN currently depends on this prefix
73+
// eslint-disable-next-line react-internal/safe-string-coercion
74+
args = args.map(function (item) {
75+
return String(item);
76+
});
77+
args.unshift('Warning: ' + format);
78+
} // We intentionally don't use spread (or .apply) directly because it
7079
// breaks IE9: https://github.com/facebook/react/issues/13610
7180
// eslint-disable-next-line react-internal/no-production-logging
7281

73-
Function.prototype.apply.call(console[level], console, argsWithFormat);
82+
83+
Function.prototype.apply.call(console[level], console, args);
7484
}
7585
}
7686

@@ -11564,22 +11574,39 @@ function defaultOnUncaughtError(error, errorInfo) {
1156411574
reportGlobalError(error);
1156511575

1156611576
{
11567-
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : '';
11568-
var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component:" : 'An error occurred in one of your React components:';
11569-
console['warn']('%s\n%s\n\n%s', componentNameMessage, componentStack || '', 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.');
11577+
var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component." : 'An error occurred in one of your React components.';
11578+
var errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.';
11579+
11580+
{
11581+
// The current Fiber is disconnected at this point which means that console printing
11582+
// cannot add a component stack since it terminates at the deletion node. This is not
11583+
// a problem for owner stacks which are not disconnected but for the parent component
11584+
// stacks we need to use the snapshot we've previously extracted.
11585+
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; // Don't transform to our wrapper
11586+
11587+
console['warn']('%s\n\n%s\n%s', componentNameMessage, errorBoundaryMessage, componentStack);
11588+
}
1157011589
}
1157111590
}
11572-
function defaultOnCaughtError(error, errorInfo) {
11591+
function defaultOnCaughtError(error$1, errorInfo) {
1157311592
// Overriding this can silence these warnings e.g. for tests.
1157411593
// See https://github.com/facebook/react/pull/13384
1157511594
// Caught by error boundary
1157611595
{
11577-
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : '';
11578-
var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; // In development, we provide our own message which includes the component stack
11596+
var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component." : 'The above error occurred in one of your React components.'; // In development, we provide our own message which includes the component stack
1157911597
// in addition to the error.
11580-
// Don't transform to our wrapper
1158111598

11582-
console['error']('%o\n\n%s\n%s\n\n%s', error, componentNameMessage, componentStack, "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + "."));
11599+
var recreateMessage = "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + ".");
11600+
11601+
{
11602+
// The current Fiber is disconnected at this point which means that console printing
11603+
// cannot add a component stack since it terminates at the deletion node. This is not
11604+
// a problem for owner stacks which are not disconnected but for the parent component
11605+
// stacks we need to use the snapshot we've previously extracted.
11606+
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; // Don't transform to our wrapper
11607+
11608+
console['error']('%o\n\n%s\n\n%s\n%s', error$1, componentNameMessage, recreateMessage, componentStack);
11609+
}
1158311610
}
1158411611
}
1158511612
function defaultOnRecoverableError(error, errorInfo) {
@@ -11651,7 +11678,11 @@ function createRootErrorUpdate(root, errorInfo, lane) {
1165111678
};
1165211679

1165311680
update.callback = function () {
11681+
var prevFiber = getCurrentFiber(); // should just be the root
11682+
11683+
setCurrentDebugFiberInDEV(errorInfo.source);
1165411684
logUncaughtError(root, errorInfo);
11685+
setCurrentDebugFiberInDEV(prevFiber);
1165511686
};
1165611687

1165711688
return update;
@@ -11678,7 +11709,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
1167811709
markFailedErrorBoundaryForHotReloading(fiber);
1167911710
}
1168011711

11712+
var prevFiber = getCurrentFiber(); // should be the error boundary
11713+
11714+
setCurrentDebugFiberInDEV(errorInfo.source);
1168111715
logCaughtError(root, fiber, errorInfo);
11716+
setCurrentDebugFiberInDEV(prevFiber);
1168211717
};
1168311718
}
1168411719

@@ -11691,7 +11726,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
1169111726
markFailedErrorBoundaryForHotReloading(fiber);
1169211727
}
1169311728

11729+
var prevFiber = getCurrentFiber(); // should be the error boundary
11730+
11731+
setCurrentDebugFiberInDEV(errorInfo.source);
1169411732
logCaughtError(root, fiber, errorInfo);
11733+
setCurrentDebugFiberInDEV(prevFiber);
1169511734

1169611735
if (typeof getDerivedStateFromError !== 'function') {
1169711736
// To preserve the preexisting retry behavior of error boundaries,
@@ -21507,7 +21546,9 @@ function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPh
2150721546
for (var i = 0; i < recoverableErrors.length; i++) {
2150821547
var recoverableError = recoverableErrors[i];
2150921548
var errorInfo = makeErrorInfo(recoverableError.stack);
21549+
setCurrentDebugFiberInDEV(recoverableError.source);
2151021550
onRecoverableError(recoverableError.value, errorInfo);
21551+
resetCurrentDebugFiberInDEV();
2151121552
}
2151221553
} // If the passive effects are the result of a discrete render, flush them
2151321554
// synchronously at the end of the current task so that the result is
@@ -23303,7 +23344,7 @@ identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transition
2330323344
return root;
2330423345
}
2330523346

23306-
var ReactVersion = '19.0.0-rc-e2db64f5';
23347+
var ReactVersion = '19.0.0-rc-47384982';
2330723348

2330823349
/*
2330923350
* The `'' + value` pattern (used in perf-sensitive code) throws for Symbol

‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react/cjs/JSXDEVRuntime-dev.js

+19-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<b9f8c9335f01163a96e896a4fafadb5a>>
10+
* @generated SignedSource<<10a7ee496c01519458a4d512d4dc4cbf>>
1111
*/
1212

1313
'use strict';
@@ -88,23 +88,33 @@ function printWarning(level, format, args) {
8888
// When changing this logic, you might want to also
8989
// update consoleWithStackDev.www.js as well.
9090
{
91+
var isErrorLogger = format === '%s\n\n%s\n' || format === '%o\n\n%s\n\n%s\n';
9192
var stack = ReactSharedInternals.getStackAddendum();
9293

9394
if (stack !== '') {
9495
format += '%s';
9596
args = args.concat([stack]);
96-
} // eslint-disable-next-line react-internal/safe-string-coercion
97-
98-
99-
var argsWithFormat = args.map(function (item) {
100-
return String(item);
101-
}); // Careful: RN currently depends on this prefix
97+
}
10298

103-
argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it
99+
if (isErrorLogger) {
100+
// Don't prefix our default logging formatting in ReactFiberErrorLoggger.
101+
// Don't toString the arguments.
102+
args.unshift(format);
103+
} else {
104+
// TODO: Remove this prefix and stop toStringing in the wrapper and
105+
// instead do it at each callsite as needed.
106+
// Careful: RN currently depends on this prefix
107+
// eslint-disable-next-line react-internal/safe-string-coercion
108+
args = args.map(function (item) {
109+
return String(item);
110+
});
111+
args.unshift('Warning: ' + format);
112+
} // We intentionally don't use spread (or .apply) directly because it
104113
// breaks IE9: https://github.com/facebook/react/issues/13610
105114
// eslint-disable-next-line react-internal/no-production-logging
106115

107-
Function.prototype.apply.call(console[level], console, argsWithFormat);
116+
117+
Function.prototype.apply.call(console[level], console, args);
108118
}
109119
}
110120

‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react/cjs/JSXRuntime-dev.js

+19-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<4c3bee042278a4a49d386c57d4f82f3b>>
10+
* @generated SignedSource<<e0d9391ce7a2f249859c8e0aea4424e0>>
1111
*/
1212

1313
'use strict';
@@ -88,23 +88,33 @@ function printWarning(level, format, args) {
8888
// When changing this logic, you might want to also
8989
// update consoleWithStackDev.www.js as well.
9090
{
91+
var isErrorLogger = format === '%s\n\n%s\n' || format === '%o\n\n%s\n\n%s\n';
9192
var stack = ReactSharedInternals.getStackAddendum();
9293

9394
if (stack !== '') {
9495
format += '%s';
9596
args = args.concat([stack]);
96-
} // eslint-disable-next-line react-internal/safe-string-coercion
97-
98-
99-
var argsWithFormat = args.map(function (item) {
100-
return String(item);
101-
}); // Careful: RN currently depends on this prefix
97+
}
10298

103-
argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it
99+
if (isErrorLogger) {
100+
// Don't prefix our default logging formatting in ReactFiberErrorLoggger.
101+
// Don't toString the arguments.
102+
args.unshift(format);
103+
} else {
104+
// TODO: Remove this prefix and stop toStringing in the wrapper and
105+
// instead do it at each callsite as needed.
106+
// Careful: RN currently depends on this prefix
107+
// eslint-disable-next-line react-internal/safe-string-coercion
108+
args = args.map(function (item) {
109+
return String(item);
110+
});
111+
args.unshift('Warning: ' + format);
112+
} // We intentionally don't use spread (or .apply) directly because it
104113
// breaks IE9: https://github.com/facebook/react/issues/13610
105114
// eslint-disable-next-line react-internal/no-production-logging
106115

107-
Function.prototype.apply.call(console[level], console, argsWithFormat);
116+
117+
Function.prototype.apply.call(console[level], console, args);
108118
}
109119
}
110120

‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react/cjs/React-dev.js

+20-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<4bef08404d3aea55caa1230f32a63bc4>>
10+
* @generated SignedSource<<99e34fed5db832c23f4f082b7bcba4d2>>
1111
*/
1212

1313
'use strict';
@@ -24,7 +24,7 @@ if (
2424
}
2525
var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags');
2626

27-
var ReactVersion = '19.0.0-rc-b0b64d87';
27+
var ReactVersion = '19.0.0-rc-6e8d1fca';
2828

2929
// Re-export dynamic flags from the internal module.
3030
var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on
@@ -153,23 +153,33 @@ function printWarning(level, format, args) {
153153
// When changing this logic, you might want to also
154154
// update consoleWithStackDev.www.js as well.
155155
{
156+
var isErrorLogger = format === '%s\n\n%s\n' || format === '%o\n\n%s\n\n%s\n';
156157
var stack = ReactSharedInternals.getStackAddendum();
157158

158159
if (stack !== '') {
159160
format += '%s';
160161
args = args.concat([stack]);
161-
} // eslint-disable-next-line react-internal/safe-string-coercion
162-
163-
164-
var argsWithFormat = args.map(function (item) {
165-
return String(item);
166-
}); // Careful: RN currently depends on this prefix
162+
}
167163

168-
argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it
164+
if (isErrorLogger) {
165+
// Don't prefix our default logging formatting in ReactFiberErrorLoggger.
166+
// Don't toString the arguments.
167+
args.unshift(format);
168+
} else {
169+
// TODO: Remove this prefix and stop toStringing in the wrapper and
170+
// instead do it at each callsite as needed.
171+
// Careful: RN currently depends on this prefix
172+
// eslint-disable-next-line react-internal/safe-string-coercion
173+
args = args.map(function (item) {
174+
return String(item);
175+
});
176+
args.unshift('Warning: ' + format);
177+
} // We intentionally don't use spread (or .apply) directly because it
169178
// breaks IE9: https://github.com/facebook/react/issues/13610
170179
// eslint-disable-next-line react-internal/no-production-logging
171180

172-
Function.prototype.apply.call(console[level], console, argsWithFormat);
181+
182+
Function.prototype.apply.call(console[level], console, args);
173183
}
174184
}
175185

Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2e3e6a9b1cc97ec91248be74565e7ccbf6946067
1+
2e540e22b2b4038a278b2875306976b016fb31a9

0 commit comments

Comments
 (0)
Please sign in to comment.