@samitouri / QOS-React-1 / commits / 433068eece

Remove top stack frame from getCurrentStack (#30306)

The full stack is the current execution stack (`new Error().stack`) + the current owner stack (`React.captureOwnerStack()`). The idea with the top frame was that when we append it to console.error we'd include both since otherwise the true reason would be obscured behind the little `>` to expand. So we'd just put both stack front and center. By adding this into getCurrentStack it was easy to use the same filtering. I never implemented in Fizz or Flight though. However, with the public API `React.captureOwnerStack()` it's not necessary to include the current stack since you already have it and you'd have filtering capabilities in user space too. Since I'm removing the component stacks from React itself we no longer need this. It's expected that maybe RDT or framework polyfill would include this same technique though.

Sebastian Markbåge committed Jul 11, 2024 at 18:34 UTC 433068eece2071a96de98b60f99ce6a9121a629c
8 files changed +25 -39
packages/react-reconciler/src/ReactCurrentFiber.js
+2 -2
@@ -33,7 +33,7 @@ export function getCurrentFiberOwnerNameInDevOrNull(): string | null {
33 return null;
34 }
35
36 -function getCurrentFiberStackInDev(stack: null | Error): string {
36 +function getCurrentFiberStackInDev(): string {
37 if (__DEV__) {
38 if (current === null) {
39 return '';
@@ -43,7 +43,7 @@ function getCurrentFiberStackInDev(stack: null | Error): string {
43 // TODO: The above comment is not actually true. We might be
44 // in a commit phase or preemptive set state callback.
45 if (enableOwnerStacks) {
46 - return getOwnerStackByFiberInDev(current, stack);
46 + return getOwnerStackByFiberInDev(current);
47 }
48 return getStackByFiberInDevAndProd(current);
49 }
packages/react-reconciler/src/ReactFiberComponentStack.js
+1 -15
@@ -91,27 +91,13 @@ function describeFunctionComponentFrameWithoutLineNumber(fn: Function): string {
91 return name ? describeBuiltInComponentFrame(name) : '';
92 }
93
94 -export function getOwnerStackByFiberInDev(
95 - workInProgress: Fiber,
96 - topStack: null | Error,
97 -): string {
94 +export function getOwnerStackByFiberInDev(workInProgress: Fiber): string {
95 if (!enableOwnerStacks || !__DEV__) {
96 return '';
97 }
98 try {
99 let info = '';
100
104 - if (topStack) {
105 - // Prefix with a filtered version of the currently executing
106 - // stack. This information will be available in the native
107 - // stack regardless but it's hidden since we're reprinting
108 - // the stack on top of it.
109 - const formattedTopStack = formatOwnerStack(topStack);
110 - if (formattedTopStack !== '') {
111 - info += '\n' + formattedTopStack;
112 - }
113 - }
114 -
101 if (workInProgress.tag === HostText) {
102 // Text nodes never have an owner/stack because they're not created through JSX.
103 // We use the parent since text nodes are always created through a host parent.
packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
+9 -5
@@ -213,14 +213,18 @@ describe('ReactLazy', () => {
213 unstable_isConcurrent: true,
214 });
215
216 + function App() {
217 + return (
218 + <Suspense fallback={<Text text="Loading..." />}>
219 + <LazyText text="Hi" />
220 + </Suspense>
221 + );
222 + }
223 +
224 let error;
225 try {
226 await act(() => {
219 - root.update(
220 - <Suspense fallback={<Text text="Loading..." />}>
221 - <LazyText text="Hi" />
222 - </Suspense>,
223 - );
227 + root.update(<App />);
228 });
229 } catch (e) {
230 error = e;
packages/react/src/ReactOwnerStack.js
+1 -1
@@ -20,5 +20,5 @@ export function captureOwnerStack(): null | string {
20 }
21 // The current stack will be the owner stack if enableOwnerStacks is true
22 // which it is always here. Otherwise it's the parent stack.
23 - return getCurrentStack(null);
23 + return getCurrentStack();
24 }
packages/react/src/ReactSharedInternalsClient.js
+2 -4
@@ -35,7 +35,7 @@ export type SharedStateClient = {
35 thrownErrors: Array<mixed>,
36
37 // ReactDebugCurrentFrame
38 - getCurrentStack: null | ((stack: null | Error) => string),
38 + getCurrentStack: null | (() => string),
39 };
40
41 export type RendererTask = boolean => RendererTask | null;
@@ -54,9 +54,7 @@ if (__DEV__) {
54 ReactSharedInternals.didUsePromise = false;
55 ReactSharedInternals.thrownErrors = [];
56 // Stack implementation injected by the current renderer.
57 - ReactSharedInternals.getCurrentStack = (null:
58 - | null
59 - | ((stack: null | Error) => string));
57 + ReactSharedInternals.getCurrentStack = (null: null | (() => string));
58 }
59
60 export default ReactSharedInternals;
packages/react/src/ReactSharedInternalsServer.js
+2 -4
@@ -38,7 +38,7 @@ export type SharedStateServer = {
38 // DEV-only
39
40 // ReactDebugCurrentFrame
41 - getCurrentStack: null | ((stack: null | Error) => string),
41 + getCurrentStack: null | (() => string),
42 };
43
44 export type RendererTask = boolean => RendererTask | null;
@@ -58,9 +58,7 @@ if (enableTaint) {
58
59 if (__DEV__) {
60 // Stack implementation injected by the current renderer.
61 - ReactSharedInternals.getCurrentStack = (null:
62 - | null
63 - | ((stack: null | Error) => string));
61 + ReactSharedInternals.getCurrentStack = (null: null | (() => string));
62 }
63
64 export default ReactSharedInternals;
packages/shared/forks/consoleWithStackDev.rn.js
+4 -4
@@ -23,7 +23,7 @@ export function setSuppressWarning(newSuppressWarning) {
23 export function warn(format, ...args) {
24 if (__DEV__) {
25 if (!suppressWarning) {
26 - printWarning('warn', format, args, new Error('react-stack-top-frame'));
26 + printWarning('warn', format, args);
27 }
28 }
29 }
@@ -31,17 +31,17 @@ export function warn(format, ...args) {
31 export function error(format, ...args) {
32 if (__DEV__) {
33 if (!suppressWarning) {
34 - printWarning('error', format, args, new Error('react-stack-top-frame'));
34 + printWarning('error', format, args);
35 }
36 }
37 }
38
39 export let isWritingAppendedStack = false;
40
41 -function printWarning(level, format, args, currentStack) {
41 +function printWarning(level, format, args) {
42 if (__DEV__) {
43 if (ReactSharedInternals.getCurrentStack) {
44 - const stack = ReactSharedInternals.getCurrentStack(currentStack);
44 + const stack = ReactSharedInternals.getCurrentStack();
45 if (stack !== '') {
46 isWritingAppendedStack = true;
47 format += '%s';
packages/shared/forks/consoleWithStackDev.www.js
+4 -4
@@ -18,7 +18,7 @@ export function setSuppressWarning(newSuppressWarning) {
18 export function warn(format, ...args) {
19 if (__DEV__) {
20 if (!suppressWarning) {
21 - printWarning('warn', format, args, new Error('react-stack-top-frame'));
21 + printWarning('warn', format, args);
22 }
23 }
24 }
@@ -26,19 +26,19 @@ export function warn(format, ...args) {
26 export function error(format, ...args) {
27 if (__DEV__) {
28 if (!suppressWarning) {
29 - printWarning('error', format, args, new Error('react-stack-top-frame'));
29 + printWarning('error', format, args);
30 }
31 }
32 }
33
34 -function printWarning(level, format, args, currentStack) {
34 +function printWarning(level, format, args) {
35 if (__DEV__) {
36 const React = require('react');
37 const ReactSharedInternals =
38 React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
39 // Defensive in case this is fired before React is initialized.
40 if (ReactSharedInternals != null && ReactSharedInternals.getCurrentStack) {
41 - const stack = ReactSharedInternals.getCurrentStack(currentStack);
41 + const stack = ReactSharedInternals.getCurrentStack();
42 if (stack !== '') {
43 format += '%s';
44 args.push(stack);