Add unknown location information to component stacks (#30290)

This is the same change as in #30289 but for the main runtime - e.g.
parent stacks in errorInfo.componentStack, appended stacks to
console.error coming from React itself and when we add virtual frames to
owner stacks.

Since we don't add location information these frames look weird to some
stack parsers - such as the native one. This is an existing issue when
you want to use some off-the-shelf parsers to parse production component
stacks for example.

While we won't add Error objects to logs ourselves necessarily, some
third party could want to do the same thing we do in DevTools and so we
should provide the same capability to just take this trace and print it
using an Error object.
This commit is contained in:
Sebastian Markbåge
2024-07-08 11:54:14 -04:00
committed by GitHub
parent 1b0132c05a
commit df783f9ea1
3 changed files with 14 additions and 4 deletions

View File

@@ -475,7 +475,7 @@ describe('ReactDOM HostSingleton', () => {
expect(hydrationErrors).toEqual([
[
"Hydration failed because the server rendered HTML didn't match the client.",
'at div',
'at div (<anonymous>)',
],
]);
expect(persistentElements).toEqual([

View File

@@ -924,7 +924,7 @@ function pushServerComponentStack(
let name = componentInfo.name;
const env = componentInfo.env;
if (env) {
name += ' (' + env + ')';
name += ' [' + env + ']';
}
task.componentStack = {
tag: 3,

View File

@@ -24,6 +24,7 @@ import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
import ReactSharedInternals from 'shared/ReactSharedInternals';
let prefix;
let suffix;
export function describeBuiltInComponentFrame(name: string): string {
if (enableComponentStackLocations) {
if (prefix === undefined) {
@@ -33,17 +34,26 @@ export function describeBuiltInComponentFrame(name: string): string {
} catch (x) {
const match = x.stack.trim().match(/\n( *(at )?)/);
prefix = (match && match[1]) || '';
suffix =
x.stack.indexOf('\n at') > -1
? // V8
' (<anonymous>)'
: // JSC/Spidermonkey
x.stack.indexOf('@') > -1
? '@unknown:0:0'
: // Other
'';
}
}
// We use the prefix to ensure our stacks line up with native stack frames.
return '\n' + prefix + name;
return '\n' + prefix + name + suffix;
} else {
return describeComponentFrame(name);
}
}
export function describeDebugInfoFrame(name: string, env: ?string): string {
return describeBuiltInComponentFrame(name + (env ? ' (' + env + ')' : ''));
return describeBuiltInComponentFrame(name + (env ? ' [' + env + ']' : ''));
}
let reentry = false;