Skip to content

Commit 5a1eb6f

Browse files
hoxyqjackpope
authored andcommitted
fix: rename bottom stack frame (#33680)
`react-stack-bottom-frame` -> `react_stack_bottom_frame`. This survives `@babel/plugin-transform-function-name`, but now frames will be displayed as `at Object.react_stack_bottom_frame (...)` in V8. Checks that were relying on exact function name match were updated to use either `.indexOf()` or `.includes()` For backwards compatibility, both React DevTools and Flight Client will look for both options. I am not so sure about the latter and if React version is locked.
1 parent 01eae20 commit 5a1eb6f

File tree

9 files changed

+47
-40
lines changed

9 files changed

+47
-40
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,7 +2438,7 @@ function buildFakeTask(
24382438
}
24392439

24402440
const createFakeJSXCallStack = {
2441-
'react-stack-bottom-frame': function (
2441+
react_stack_bottom_frame: function (
24422442
response: Response,
24432443
stack: ReactStackTrace,
24442444
environmentName: string,
@@ -2459,7 +2459,7 @@ const createFakeJSXCallStackInDEV: (
24592459
environmentName: string,
24602460
) => Error = __DEV__
24612461
? // We use this technique to trick minifiers to preserve the function name.
2462-
(createFakeJSXCallStack['react-stack-bottom-frame'].bind(
2462+
(createFakeJSXCallStack.react_stack_bottom_frame.bind(
24632463
createFakeJSXCallStack,
24642464
): any)
24652465
: (null: any);
@@ -2563,7 +2563,7 @@ function getCurrentStackInDEV(): string {
25632563
}
25642564

25652565
const replayConsoleWithCallStack = {
2566-
'react-stack-bottom-frame': function (
2566+
react_stack_bottom_frame: function (
25672567
response: Response,
25682568
methodName: string,
25692569
stackTrace: ReactStackTrace,
@@ -2614,7 +2614,7 @@ const replayConsoleWithCallStackInDEV: (
26142614
args: Array<mixed>,
26152615
) => void = __DEV__
26162616
? // We use this technique to trick minifiers to preserve the function name.
2617-
(replayConsoleWithCallStack['react-stack-bottom-frame'].bind(
2617+
(replayConsoleWithCallStack.react_stack_bottom_frame.bind(
26182618
replayConsoleWithCallStack,
26192619
): any)
26202620
: (null: any);

packages/react-devtools-shared/src/backend/shared/DevToolsOwnerStack.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ export function formatOwnerStackString(stack: string): string {
2929
// Pop the JSX frame.
3030
stack = stack.slice(idx + 1);
3131
}
32-
idx = stack.indexOf('react-stack-bottom-frame');
32+
idx = stack.indexOf('react_stack_bottom_frame');
33+
if (idx === -1) {
34+
idx = stack.indexOf('react-stack-bottom-frame');
35+
}
3336
if (idx !== -1) {
3437
idx = stack.lastIndexOf('\n', idx);
3538
}

packages/react-devtools-shared/src/backend/utils/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,11 @@ function collectStackTrace(
358358
// We mirror how V8 serializes stack frames and how we later parse them.
359359
for (let i = 0; i < structuredStackTrace.length; i++) {
360360
const callSite = structuredStackTrace[i];
361-
if (callSite.getFunctionName() === 'react-stack-bottom-frame') {
361+
const name = callSite.getFunctionName();
362+
if (
363+
name.includes('react_stack_bottom_frame') ||
364+
name.includes('react-stack-bottom-frame')
365+
) {
362366
// We pick the last frame that matches before the bottom frame since
363367
// that will be immediately inside the component as opposed to some helper.
364368
// If we don't find a bottom frame then we bail to string parsing.

packages/react-reconciler/src/ReactFiberCallUserSpace.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {enableUseEffectCRUDOverload} from 'shared/ReactFeatureFlags';
2424
// TODO: Consider marking the whole bundle instead of these boundaries.
2525

2626
const callComponent = {
27-
'react-stack-bottom-frame': function <Props, Arg, R>(
27+
react_stack_bottom_frame: function <Props, Arg, R>(
2828
Component: (p: Props, arg: Arg) => R,
2929
props: Props,
3030
secondArg: Arg,
@@ -46,7 +46,7 @@ export const callComponentInDEV: <Props, Arg, R>(
4646
secondArg: Arg,
4747
) => R = __DEV__
4848
? // We use this technique to trick minifiers to preserve the function name.
49-
(callComponent['react-stack-bottom-frame'].bind(callComponent): any)
49+
(callComponent.react_stack_bottom_frame.bind(callComponent): any)
5050
: (null: any);
5151

5252
interface ClassInstance<R> {
@@ -62,7 +62,7 @@ interface ClassInstance<R> {
6262
}
6363

6464
const callRender = {
65-
'react-stack-bottom-frame': function <R>(instance: ClassInstance<R>): R {
65+
react_stack_bottom_frame: function <R>(instance: ClassInstance<R>): R {
6666
const wasRendering = isRendering;
6767
setIsRendering(true);
6868
try {
@@ -77,11 +77,11 @@ const callRender = {
7777
export const callRenderInDEV: <R>(instance: ClassInstance<R>) => R => R =
7878
__DEV__
7979
? // We use this technique to trick minifiers to preserve the function name.
80-
(callRender['react-stack-bottom-frame'].bind(callRender): any)
80+
(callRender.react_stack_bottom_frame.bind(callRender): any)
8181
: (null: any);
8282

8383
const callComponentDidMount = {
84-
'react-stack-bottom-frame': function (
84+
react_stack_bottom_frame: function (
8585
finishedWork: Fiber,
8686
instance: ClassInstance<any>,
8787
): void {
@@ -98,13 +98,13 @@ export const callComponentDidMountInDEV: (
9898
instance: ClassInstance<any>,
9999
) => void = __DEV__
100100
? // We use this technique to trick minifiers to preserve the function name.
101-
(callComponentDidMount['react-stack-bottom-frame'].bind(
101+
(callComponentDidMount.react_stack_bottom_frame.bind(
102102
callComponentDidMount,
103103
): any)
104104
: (null: any);
105105

106106
const callComponentDidUpdate = {
107-
'react-stack-bottom-frame': function (
107+
react_stack_bottom_frame: function (
108108
finishedWork: Fiber,
109109
instance: ClassInstance<any>,
110110
prevProps: Object,
@@ -127,13 +127,13 @@ export const callComponentDidUpdateInDEV: (
127127
snaphot: Object,
128128
) => void = __DEV__
129129
? // We use this technique to trick minifiers to preserve the function name.
130-
(callComponentDidUpdate['react-stack-bottom-frame'].bind(
130+
(callComponentDidUpdate.react_stack_bottom_frame.bind(
131131
callComponentDidUpdate,
132132
): any)
133133
: (null: any);
134134

135135
const callComponentDidCatch = {
136-
'react-stack-bottom-frame': function (
136+
react_stack_bottom_frame: function (
137137
instance: ClassInstance<any>,
138138
errorInfo: CapturedValue<mixed>,
139139
): void {
@@ -150,13 +150,13 @@ export const callComponentDidCatchInDEV: (
150150
errorInfo: CapturedValue<mixed>,
151151
) => void = __DEV__
152152
? // We use this technique to trick minifiers to preserve the function name.
153-
(callComponentDidCatch['react-stack-bottom-frame'].bind(
153+
(callComponentDidCatch.react_stack_bottom_frame.bind(
154154
callComponentDidCatch,
155155
): any)
156156
: (null: any);
157157

158158
const callComponentWillUnmount = {
159-
'react-stack-bottom-frame': function (
159+
react_stack_bottom_frame: function (
160160
current: Fiber,
161161
nearestMountedAncestor: Fiber | null,
162162
instance: ClassInstance<any>,
@@ -175,13 +175,13 @@ export const callComponentWillUnmountInDEV: (
175175
instance: ClassInstance<any>,
176176
) => void = __DEV__
177177
? // We use this technique to trick minifiers to preserve the function name.
178-
(callComponentWillUnmount['react-stack-bottom-frame'].bind(
178+
(callComponentWillUnmount.react_stack_bottom_frame.bind(
179179
callComponentWillUnmount,
180180
): any)
181181
: (null: any);
182182

183183
const callCreate = {
184-
'react-stack-bottom-frame': function (
184+
react_stack_bottom_frame: function (
185185
effect: Effect,
186186
): (() => void) | {...} | void | null {
187187
if (!enableUseEffectCRUDOverload) {
@@ -234,11 +234,11 @@ const callCreate = {
234234

235235
export const callCreateInDEV: (effect: Effect) => (() => void) | void = __DEV__
236236
? // We use this technique to trick minifiers to preserve the function name.
237-
(callCreate['react-stack-bottom-frame'].bind(callCreate): any)
237+
(callCreate.react_stack_bottom_frame.bind(callCreate): any)
238238
: (null: any);
239239

240240
const callDestroy = {
241-
'react-stack-bottom-frame': function (
241+
react_stack_bottom_frame: function (
242242
current: Fiber,
243243
nearestMountedAncestor: Fiber | null,
244244
destroy: () => void,
@@ -257,11 +257,11 @@ export const callDestroyInDEV: (
257257
destroy: (() => void) | (({...}) => void),
258258
) => void = __DEV__
259259
? // We use this technique to trick minifiers to preserve the function name.
260-
(callDestroy['react-stack-bottom-frame'].bind(callDestroy): any)
260+
(callDestroy.react_stack_bottom_frame.bind(callDestroy): any)
261261
: (null: any);
262262

263263
const callLazyInit = {
264-
'react-stack-bottom-frame': function (lazy: LazyComponent<any, any>): any {
264+
react_stack_bottom_frame: function (lazy: LazyComponent<any, any>): any {
265265
const payload = lazy._payload;
266266
const init = lazy._init;
267267
return init(payload);
@@ -270,5 +270,5 @@ const callLazyInit = {
270270

271271
export const callLazyInitInDEV: (lazy: LazyComponent<any, any>) => any = __DEV__
272272
? // We use this technique to trick minifiers to preserve the function name.
273-
(callLazyInit['react-stack-bottom-frame'].bind(callLazyInit): any)
273+
(callLazyInit.react_stack_bottom_frame.bind(callLazyInit): any)
274274
: (null: any);

packages/react-server/src/ReactFizzCallUserSpace.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {LazyComponent} from 'react/src/ReactLazy';
1313
// TODO: Consider marking the whole bundle instead of these boundaries.
1414

1515
const callComponent = {
16-
'react-stack-bottom-frame': function <Props, Arg, R>(
16+
react_stack_bottom_frame: function <Props, Arg, R>(
1717
Component: (p: Props, arg: Arg) => R,
1818
props: Props,
1919
secondArg: Arg,
@@ -28,27 +28,27 @@ export const callComponentInDEV: <Props, Arg, R>(
2828
secondArg: Arg,
2929
) => R = __DEV__
3030
? // We use this technique to trick minifiers to preserve the function name.
31-
(callComponent['react-stack-bottom-frame'].bind(callComponent): any)
31+
(callComponent.react_stack_bottom_frame.bind(callComponent): any)
3232
: (null: any);
3333

3434
interface ClassInstance<R> {
3535
render(): R;
3636
}
3737

3838
const callRender = {
39-
'react-stack-bottom-frame': function <R>(instance: ClassInstance<R>): R {
39+
react_stack_bottom_frame: function <R>(instance: ClassInstance<R>): R {
4040
return instance.render();
4141
},
4242
};
4343

4444
export const callRenderInDEV: <R>(instance: ClassInstance<R>) => R => R =
4545
__DEV__
4646
? // We use this technique to trick minifiers to preserve the function name.
47-
(callRender['react-stack-bottom-frame'].bind(callRender): any)
47+
(callRender.react_stack_bottom_frame.bind(callRender): any)
4848
: (null: any);
4949

5050
const callLazyInit = {
51-
'react-stack-bottom-frame': function (lazy: LazyComponent<any, any>): any {
51+
react_stack_bottom_frame: function (lazy: LazyComponent<any, any>): any {
5252
const payload = lazy._payload;
5353
const init = lazy._init;
5454
return init(payload);
@@ -57,5 +57,5 @@ const callLazyInit = {
5757

5858
export const callLazyInitInDEV: (lazy: LazyComponent<any, any>) => any = __DEV__
5959
? // We use this technique to trick minifiers to preserve the function name.
60-
(callLazyInit['react-stack-bottom-frame'].bind(callLazyInit): any)
60+
(callLazyInit.react_stack_bottom_frame.bind(callLazyInit): any)
6161
: (null: any);

packages/react-server/src/ReactFlightCallUserSpace.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {setCurrentOwner} from './flight/ReactFlightCurrentOwner';
1919
// TODO: Consider marking the whole bundle instead of these boundaries.
2020

2121
const callComponent = {
22-
'react-stack-bottom-frame': function <Props, R>(
22+
react_stack_bottom_frame: function <Props, R>(
2323
Component: (p: Props, arg: void) => R,
2424
props: Props,
2525
componentDebugInfo: ReactComponentInfo,
@@ -41,11 +41,11 @@ export const callComponentInDEV: <Props, R>(
4141
componentDebugInfo: ReactComponentInfo,
4242
) => R = __DEV__
4343
? // We use this technique to trick minifiers to preserve the function name.
44-
(callComponent['react-stack-bottom-frame'].bind(callComponent): any)
44+
(callComponent.react_stack_bottom_frame.bind(callComponent): any)
4545
: (null: any);
4646

4747
const callLazyInit = {
48-
'react-stack-bottom-frame': function (lazy: LazyComponent<any, any>): any {
48+
react_stack_bottom_frame: function (lazy: LazyComponent<any, any>): any {
4949
const payload = lazy._payload;
5050
const init = lazy._init;
5151
return init(payload);
@@ -54,11 +54,11 @@ const callLazyInit = {
5454

5555
export const callLazyInitInDEV: (lazy: LazyComponent<any, any>) => any = __DEV__
5656
? // We use this technique to trick minifiers to preserve the function name.
57-
(callLazyInit['react-stack-bottom-frame'].bind(callLazyInit): any)
57+
(callLazyInit.react_stack_bottom_frame.bind(callLazyInit): any)
5858
: (null: any);
5959

6060
const callIterator = {
61-
'react-stack-bottom-frame': function (
61+
react_stack_bottom_frame: function (
6262
iterator: $AsyncIterator<ReactClientValue, ReactClientValue, void>,
6363
progress: (
6464
entry:
@@ -81,5 +81,5 @@ export const callIteratorInDEV: (
8181
error: (reason: mixed) => void,
8282
) => void = __DEV__
8383
? // We use this technique to trick minifiers to preserve the function name.
84-
(callIterator['react-stack-bottom-frame'].bind(callIterator): any)
84+
(callIterator.react_stack_bottom_frame.bind(callIterator): any)
8585
: (null: any);

packages/react-server/src/ReactFlightStackConfigV8.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function parseStackTrace(
4545
// don't want/need.
4646
stack = stack.slice(29);
4747
}
48-
let idx = stack.indexOf('react-stack-bottom-frame');
48+
let idx = stack.indexOf('react_stack_bottom_frame');
4949
if (idx !== -1) {
5050
idx = stack.lastIndexOf('\n', idx);
5151
}

packages/react/src/jsx/ReactJSXElement.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function UnknownOwner() {
6666
return (() => Error('react-stack-top-frame'))();
6767
}
6868
const createFakeCallStack = {
69-
'react-stack-bottom-frame': function (callStackForError) {
69+
react_stack_bottom_frame: function (callStackForError) {
7070
return callStackForError();
7171
},
7272
};
@@ -81,7 +81,7 @@ if (__DEV__) {
8181
didWarnAboutElementRef = {};
8282

8383
// We use this technique to trick minifiers to preserve the function name.
84-
unknownOwnerDebugStack = createFakeCallStack['react-stack-bottom-frame'].bind(
84+
unknownOwnerDebugStack = createFakeCallStack.react_stack_bottom_frame.bind(
8585
createFakeCallStack,
8686
UnknownOwner,
8787
)();

packages/shared/ReactOwnerStackFrames.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export function formatOwnerStack(error: Error): string {
2424
// Pop the JSX frame.
2525
stack = stack.slice(idx + 1);
2626
}
27-
idx = stack.indexOf('react-stack-bottom-frame');
27+
idx = stack.indexOf('react_stack_bottom_frame');
2828
if (idx !== -1) {
2929
idx = stack.lastIndexOf('\n', idx);
3030
}

0 commit comments

Comments
 (0)