From df783f9ea1b6f95e05f830602da1de5ffb325d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 8 Jul 2024 11:54:14 -0400 Subject: [PATCH] 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. --- .../__tests__/ReactDOMSingletonComponents-test.js | 2 +- packages/react-server/src/ReactFizzServer.js | 2 +- packages/shared/ReactComponentStackFrame.js | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMSingletonComponents-test.js b/packages/react-dom/src/__tests__/ReactDOMSingletonComponents-test.js index b1d0a9cb23..ff6e6968ca 100644 --- a/packages/react-dom/src/__tests__/ReactDOMSingletonComponents-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMSingletonComponents-test.js @@ -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 ()', ], ]); expect(persistentElements).toEqual([ diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index e1e180f2f7..cf44e055ca 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -924,7 +924,7 @@ function pushServerComponentStack( let name = componentInfo.name; const env = componentInfo.env; if (env) { - name += ' (' + env + ')'; + name += ' [' + env + ']'; } task.componentStack = { tag: 3, diff --git a/packages/shared/ReactComponentStackFrame.js b/packages/shared/ReactComponentStackFrame.js index 34c9487a30..25f98bd2f4 100644 --- a/packages/shared/ReactComponentStackFrame.js +++ b/packages/shared/ReactComponentStackFrame.js @@ -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 + ' ()' + : // 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;