mirror of
https://github.com/facebook/react.git
synced 2026-02-24 12:43:00 +00:00
Ideally we wouldn't need to filter out React internals and it'd just be covered by ignore listing by any downstream tool. E.g. a framework using captureOwnerStack could have its own ignore listing. Printed owner stacks would get browser source map ignore-listing. React DevTools could have its own ignore list for internals. However, it's nice to be able to provide nice owner stacks without a bunch of noise by default. Especially on the server since they have to be serialized. We currently call each function that calls into user space and track its stack frame. However, this needs code for checking each one and doesn't let us work across bundles. Instead, we can name each of these frame something predictable by giving the function a name. Unfortunately, it's a common practice to rename functions or inline them in compilers. Even if we didn't, others downstream from us or a dev-mode minifier could. I use this `.bind()` trick to avoid minifying these functions and ensure they get a unique name added to them in all browsers. It's not 100% fool proof since a smart enough compiler could also discover that the `this` value is not used and strip out the function and then inline it but nobody does this yet at least. This lets us find the bottom stack easily from stack traces just by looking for the name.
62 lines
1.8 KiB
JavaScript
62 lines
1.8 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import type {LazyComponent} from 'react/src/ReactLazy';
|
|
|
|
// These indirections exists so we can exclude its stack frame in DEV (and anything below it).
|
|
// TODO: Consider marking the whole bundle instead of these boundaries.
|
|
|
|
const callComponent = {
|
|
'react-stack-bottom-frame': function <Props, Arg, R>(
|
|
Component: (p: Props, arg: Arg) => R,
|
|
props: Props,
|
|
secondArg: Arg,
|
|
): R {
|
|
return Component(props, secondArg);
|
|
},
|
|
};
|
|
|
|
export const callComponentInDEV: <Props, Arg, R>(
|
|
Component: (p: Props, arg: Arg) => R,
|
|
props: Props,
|
|
secondArg: Arg,
|
|
) => R = __DEV__
|
|
? // We use this technique to trick minifiers to preserve the function name.
|
|
(callComponent['react-stack-bottom-frame'].bind(callComponent): any)
|
|
: (null: any);
|
|
|
|
interface ClassInstance<R> {
|
|
render(): R;
|
|
}
|
|
|
|
const callRender = {
|
|
'react-stack-bottom-frame': function <R>(instance: ClassInstance<R>): R {
|
|
return instance.render();
|
|
},
|
|
};
|
|
|
|
export const callRenderInDEV: <R>(instance: ClassInstance<R>) => R => R =
|
|
__DEV__
|
|
? // We use this technique to trick minifiers to preserve the function name.
|
|
(callRender['react-stack-bottom-frame'].bind(callRender): any)
|
|
: (null: any);
|
|
|
|
const callLazyInit = {
|
|
'react-stack-bottom-frame': function (lazy: LazyComponent<any, any>): any {
|
|
const payload = lazy._payload;
|
|
const init = lazy._init;
|
|
return init(payload);
|
|
},
|
|
};
|
|
|
|
export const callLazyInitInDEV: (lazy: LazyComponent<any, any>) => any = __DEV__
|
|
? // We use this technique to trick minifiers to preserve the function name.
|
|
(callLazyInit['react-stack-bottom-frame'].bind(callLazyInit): any)
|
|
: (null: any);
|