@samitouri / QOS-React-2 / commits / 4169420198

Refactor Component Stack Traces (#18495)

* Add feature flag * Split stack from current fiber You can get stack from any fiber, not just current. * Refactor description of component frames These should use fiber tags for switching. This also puts the relevant code behind DEV flags. * We no longer expose StrictMode in component stacks They're not super useful and will go away later anyway. * Update tests Context is no longer part of SSR stacks. This was already the case on the client. forwardRef no longer is wrapped on the stack. It's still in getComponentName but it's probably just noise in stacks. Eventually we'll remove the wrapper so it'll go away anyway. If we use native stack frames they won't have this extra wrapper. It also doesn't pick up displayName from the outer wrapper. We could maybe transfer it but this will also be fixed by removing the wrapper. * Forward displayName onto the inner function for forwardRef and memo in DEV This allows them to show up in stack traces. I'm not doing this for lazy because lazy is supposed to be called on the consuming side so you shouldn't assign it a name on that end. Especially not one that mutates the inner. * Use multiple instances of the fake component We mutate the inner component for its name so we need multiple copies.

Sebastian Markbåge committed Apr 6, 2020 at 15:43 UTC 41694201988c5e651f0c3bc69921d5c9717be88b
33 files changed +327 -138
packages/react-devtools-shared/src/__tests__/__snapshots__/store-test.js.snap
+3 -3
@@ -619,11 +619,11 @@ exports[`Store should show the right display names for special component types 1
619 <MyComponent>
620 <MyComponent> [ForwardRef]
621 ▾ <Anonymous> [ForwardRef]
622 - <MyComponent>
622 + <MyComponent2>
623 <Custom> [ForwardRef]
624 - <MyComponent> [Memo]
624 + <MyComponent4> [Memo]
625 ▾ <MyComponent> [Memo]
626 <MyComponent> [ForwardRef]
627 ▾ <Suspense>
628 - <MyComponent>
628 + <MyComponent5>
629 `;
packages/react-devtools-shared/src/__tests__/store-test.js
+8 -4
@@ -856,16 +856,20 @@ describe('Store', () => {
856
857 const MyComponent = (props, ref) => null;
858 const FowardRefComponent = React.forwardRef(MyComponent);
859 + const MyComponent2 = (props, ref) => null;
860 const FowardRefComponentWithAnonymousFunction = React.forwardRef(() => (
860 - <MyComponent />
861 + <MyComponent2 />
862 ));
863 + const MyComponent3 = (props, ref) => null;
864 const FowardRefComponentWithCustomDisplayName = React.forwardRef(
863 - MyComponent,
865 + MyComponent3,
866 );
867 FowardRefComponentWithCustomDisplayName.displayName = 'Custom';
866 - const MemoComponent = React.memo(MyComponent);
868 + const MyComponent4 = (props, ref) => null;
869 + const MemoComponent = React.memo(MyComponent4);
870 const MemoForwardRefComponent = React.memo(FowardRefComponent);
868 - const LazyComponent = React.lazy(() => fakeImport(MyComponent));
871 + const MyComponent5 = (props, ref) => null;
872 + const LazyComponent = React.lazy(() => fakeImport(MyComponent5));
873
874 const App = () => (
875 <React.Fragment>
packages/react-dom/src/__tests__/findDOMNode-test.js
+1 -3
@@ -124,7 +124,6 @@ describe('findDOMNode', () => {
124 'Learn more about using refs safely here: ' +
125 'https://fb.me/react-strict-mode-find-node' +
126 '\n in div (at **)' +
127 - '\n in StrictMode (at **)' +
127 '\n in ContainsStrictModeChild (at **)',
128 ]);
129 expect(match).toBe(child);
@@ -154,8 +153,7 @@ describe('findDOMNode', () => {
153 'Learn more about using refs safely here: ' +
154 'https://fb.me/react-strict-mode-find-node' +
155 '\n in div (at **)' +
157 - '\n in IsInStrictMode (at **)' +
158 - '\n in StrictMode (at **)',
156 + '\n in IsInStrictMode (at **)',
157 ]);
158 expect(match).toBe(child);
159 });
packages/react-dom/src/server/ReactPartialRenderer.js
+6 -6
@@ -15,7 +15,7 @@ import type {ReactProvider, ReactContext} from 'shared/ReactTypes';
15 import * as React from 'react';
16 import invariant from 'shared/invariant';
17 import getComponentName from 'shared/getComponentName';
18 -import describeComponentFrame from 'shared/describeComponentFrame';
18 +import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
19 import ReactSharedInternals from 'shared/ReactSharedInternals';
20 import {
21 warnAboutDeprecatedLifecycles,
@@ -112,11 +112,11 @@ if (__DEV__) {
112 };
113
114 describeStackFrame = function(element): string {
115 - const source = element._source;
116 - const type = element.type;
117 - const name = getComponentName(type);
118 - const ownerName = null;
119 - return describeComponentFrame(name, source, ownerName);
115 + return describeUnknownElementTypeFrameInDEV(
116 + element.type,
117 + element._source,
118 + null,
119 + );
120 };
121
122 pushCurrentDebugStack = function(stack: Array<Frame>) {
packages/react-native-renderer/src/ReactNativeRenderer.js
+1 -1
@@ -25,7 +25,7 @@ import {
25 getPublicRootInstance,
26 } from 'react-reconciler/src/ReactFiberReconciler';
27 // TODO: direct imports like some-package/src/* are bad. Fix me.
28 -import {getStackByFiberInDevAndProd} from 'react-reconciler/src/ReactCurrentFiber';
28 +import {getStackByFiberInDevAndProd} from 'react-reconciler/src/ReactFiberComponentStack';
29 import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
30 import {
31 setBatchingImplementation,
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+2 -6
@@ -773,7 +773,6 @@ describe('ReactFabric', () => {
773 'Learn more about using refs safely here: ' +
774 'https://fb.me/react-strict-mode-find-node' +
775 '\n in RCTView (at **)' +
776 - '\n in StrictMode (at **)' +
776 '\n in ContainsStrictModeChild (at **)',
777 ]);
778 expect(match).toBe(child);
@@ -811,8 +810,7 @@ describe('ReactFabric', () => {
810 'Learn more about using refs safely here: ' +
811 'https://fb.me/react-strict-mode-find-node' +
812 '\n in RCTView (at **)' +
814 - '\n in IsInStrictMode (at **)' +
815 - '\n in StrictMode (at **)',
813 + '\n in IsInStrictMode (at **)',
814 ]);
815 expect(match).toBe(child);
816 });
@@ -846,7 +844,6 @@ describe('ReactFabric', () => {
844 'Learn more about using refs safely here: ' +
845 'https://fb.me/react-strict-mode-find-node' +
846 '\n in RCTView (at **)' +
849 - '\n in StrictMode (at **)' +
847 '\n in ContainsStrictModeChild (at **)',
848 ]);
849 expect(match).toBe(child._nativeTag);
@@ -882,8 +879,7 @@ describe('ReactFabric', () => {
879 'Learn more about using refs safely here: ' +
880 'https://fb.me/react-strict-mode-find-node' +
881 '\n in RCTView (at **)' +
885 - '\n in IsInStrictMode (at **)' +
886 - '\n in StrictMode (at **)',
882 + '\n in IsInStrictMode (at **)',
883 ]);
884 expect(match).toBe(child._nativeTag);
885 });
packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js
+2 -6
@@ -483,7 +483,6 @@ describe('ReactNative', () => {
483 'Learn more about using refs safely here: ' +
484 'https://fb.me/react-strict-mode-find-node' +
485 '\n in RCTView (at **)' +
486 - '\n in StrictMode (at **)' +
486 '\n in ContainsStrictModeChild (at **)',
487 ]);
488 expect(match).toBe(child);
@@ -521,8 +520,7 @@ describe('ReactNative', () => {
520 'Learn more about using refs safely here: ' +
521 'https://fb.me/react-strict-mode-find-node' +
522 '\n in RCTView (at **)' +
524 - '\n in IsInStrictMode (at **)' +
525 - '\n in StrictMode (at **)',
523 + '\n in IsInStrictMode (at **)',
524 ]);
525 expect(match).toBe(child);
526 });
@@ -556,7 +554,6 @@ describe('ReactNative', () => {
554 'Learn more about using refs safely here: ' +
555 'https://fb.me/react-strict-mode-find-node' +
556 '\n in RCTView (at **)' +
559 - '\n in StrictMode (at **)' +
557 '\n in ContainsStrictModeChild (at **)',
558 ]);
559 expect(match).toBe(child._nativeTag);
@@ -592,8 +589,7 @@ describe('ReactNative', () => {
589 'Learn more about using refs safely here: ' +
590 'https://fb.me/react-strict-mode-find-node' +
591 '\n in RCTView (at **)' +
595 - '\n in IsInStrictMode (at **)' +
596 - '\n in StrictMode (at **)',
592 + '\n in IsInStrictMode (at **)',
593 ]);
594 expect(match).toBe(child._nativeTag);
595 });
packages/react-reconciler/src/ReactCapturedValue.js
+1 -1
@@ -9,7 +9,7 @@
9
10 import type {Fiber} from './ReactFiber';
11
12 -import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
12 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
13
14 export type CapturedValue<T> = {|
15 value: T,
packages/react-reconciler/src/ReactChildFiber.js
+2 -4
@@ -44,10 +44,8 @@ import {
44 createFiberFromPortal,
45 } from './ReactFiber';
46 import {emptyRefsObject} from './ReactFiberClassComponent';
47 -import {
48 - getCurrentFiberStackInDev,
49 - getStackByFiberInDevAndProd,
50 -} from './ReactCurrentFiber';
47 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
48 +import {getCurrentFiberStackInDev} from './ReactCurrentFiber';
49 import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading';
50 import {StrictMode} from './ReactTypeOfMode';
51
packages/react-reconciler/src/ReactCurrentFiber.js
+1 -40
@@ -10,50 +10,11 @@
10 import type {Fiber} from './ReactFiber';
11
12 import ReactSharedInternals from 'shared/ReactSharedInternals';
13 -import {
14 - HostRoot,
15 - HostPortal,
16 - HostText,
17 - Fragment,
18 - ContextProvider,
19 - ContextConsumer,
20 -} from './ReactWorkTags';
21 -import describeComponentFrame from 'shared/describeComponentFrame';
13 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
14 import getComponentName from 'shared/getComponentName';
15
16 const ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
17
26 -function describeFiber(fiber: Fiber): string {
27 - switch (fiber.tag) {
28 - case HostRoot:
29 - case HostPortal:
30 - case HostText:
31 - case Fragment:
32 - case ContextProvider:
33 - case ContextConsumer:
34 - return '';
35 - default:
36 - const owner = fiber._debugOwner;
37 - const source = fiber._debugSource;
38 - const name = getComponentName(fiber.type);
39 - let ownerName = null;
40 - if (owner) {
41 - ownerName = getComponentName(owner.type);
42 - }
43 - return describeComponentFrame(name, source, ownerName);
44 - }
45 -}
46 -
47 -export function getStackByFiberInDevAndProd(workInProgress: Fiber): string {
48 - let info = '';
49 - let node = workInProgress;
50 - do {
51 - info += describeFiber(node);
52 - node = node.return;
53 - } while (node);
54 - return info;
55 -}
56 -
18 export let current: Fiber | null = null;
19 export let isRendering: boolean = false;
20
packages/react-reconciler/src/ReactFiberCommitWork.js
+1 -1
@@ -73,7 +73,7 @@ import getComponentName from 'shared/getComponentName';
73 import invariant from 'shared/invariant';
74
75 import {onCommitUnmount} from './ReactFiberDevToolsHook';
76 -import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
76 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
77 import {resolveDefaultProps} from './ReactFiberLazyComponent';
78 import {
79 getCommitTime,
packages/react-reconciler/src/ReactFiberComponentStack.js new
+72
@@ -0,0 +1,72 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {Fiber} from './ReactFiber';
11 +
12 +import {
13 + HostComponent,
14 + LazyComponent,
15 + SuspenseComponent,
16 + SuspenseListComponent,
17 + FunctionComponent,
18 + IndeterminateComponent,
19 + ForwardRef,
20 + MemoComponent,
21 + SimpleMemoComponent,
22 + Block,
23 + ClassComponent,
24 +} from './ReactWorkTags';
25 +import {
26 + describeBuiltInComponentFrame,
27 + describeFunctionComponentFrame,
28 + describeClassComponentFrame,
29 +} from 'shared/ReactComponentStackFrame';
30 +
31 +function describeFiber(fiber: Fiber): string {
32 + const owner: null | Function = __DEV__
33 + ? fiber._debugOwner
34 + ? fiber._debugOwner.type
35 + : null
36 + : null;
37 + const source = __DEV__ ? fiber._debugSource : null;
38 + switch (fiber.tag) {
39 + case HostComponent:
40 + return describeBuiltInComponentFrame(fiber.type, source, owner);
41 + case LazyComponent:
42 + return describeBuiltInComponentFrame('Lazy', source, owner);
43 + case SuspenseComponent:
44 + return describeBuiltInComponentFrame('Suspense', source, owner);
45 + case SuspenseListComponent:
46 + return describeBuiltInComponentFrame('SuspenseList', source, owner);
47 + case FunctionComponent:
48 + case IndeterminateComponent:
49 + case SimpleMemoComponent:
50 + return describeFunctionComponentFrame(fiber.type, source, owner);
51 + case ForwardRef:
52 + return describeFunctionComponentFrame(fiber.type.render, source, owner);
53 + case MemoComponent:
54 + return describeFunctionComponentFrame(fiber.type.type, source, owner);
55 + case Block:
56 + return describeFunctionComponentFrame(fiber.type._render, source, owner);
57 + case ClassComponent:
58 + return describeClassComponentFrame(fiber.type, source, owner);
59 + default:
60 + return '';
61 + }
62 +}
63 +
64 +export function getStackByFiberInDevAndProd(workInProgress: Fiber): string {
65 + let info = '';
66 + let node = workInProgress;
67 + do {
68 + info += describeFiber(node);
69 + node = node.return;
70 + } while (node);
71 + return info;
72 +}
packages/react-reconciler/src/ReactFiberReconciler.old.js
+1 -1
@@ -69,8 +69,8 @@ import {
69 IsThisRendererActing,
70 } from './ReactFiberWorkLoop';
71 import {createUpdate, enqueueUpdate} from './ReactUpdateQueue';
72 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
73 import {
73 - getStackByFiberInDevAndProd,
74 isRendering as ReactCurrentFiberIsRendering,
75 current as ReactCurrentFiberCurrent,
76 } from './ReactCurrentFiber';
packages/react-reconciler/src/ReactFiberThrow.js
+1 -1
@@ -40,7 +40,7 @@ import {
40 ForceUpdate,
41 enqueueUpdate,
42 } from './ReactUpdateQueue';
43 -import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
43 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
44 import {markFailedErrorBoundaryForHotReloading} from './ReactFiberHotReloading';
45 import {
46 suspenseStackCursor,
packages/react-reconciler/src/ReactFiberWorkLoop.js
+1 -1
@@ -159,11 +159,11 @@ import {
159 // DEV stuff
160 import getComponentName from 'shared/getComponentName';
161 import ReactStrictModeWarnings from './ReactStrictModeWarnings';
162 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
163 import {
164 isRendering as ReactCurrentDebugFiberIsRenderingInDEV,
165 resetCurrentFiber as resetCurrentDebugFiberInDEV,
166 setCurrentFiber as setCurrentDebugFiberInDEV,
166 - getStackByFiberInDevAndProd,
167 } from './ReactCurrentFiber';
168 import {
169 invokeGuardedCallback,
packages/react-reconciler/src/ReactStrictModeWarnings.js
+1 -1
@@ -9,7 +9,7 @@
9
10 import type {Fiber} from './ReactFiber';
11
12 -import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
12 +import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack';
13
14 import getComponentName from 'shared/getComponentName';
15 import {StrictMode} from './ReactTypeOfMode';
packages/react/src/ReactDebugCurrentFrame.js
+4 -6
@@ -9,8 +9,7 @@
9
10 import type {ReactElement} from 'shared/ReactElementType';
11
12 -import describeComponentFrame from 'shared/describeComponentFrame';
13 -import getComponentName from 'shared/getComponentName';
12 +import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
13
14 const ReactDebugCurrentFrame = {};
15
@@ -38,12 +37,11 @@ if (__DEV__) {
37
38 // Add an extra top frame while an element is being validated
39 if (currentlyValidatingElement) {
41 - const name = getComponentName(currentlyValidatingElement.type);
40 const owner = currentlyValidatingElement._owner;
43 - stack += describeComponentFrame(
44 - name,
41 + stack += describeUnknownElementTypeFrameInDEV(
42 + currentlyValidatingElement.type,
43 currentlyValidatingElement._source,
46 - owner && getComponentName(owner.type),
44 + owner ? owner.type : null,
45 );
46 }
47
packages/react/src/ReactForwardRef.js
+18 -1
@@ -43,8 +43,25 @@ export function forwardRef<Props, ElementType: React$ElementType>(
43 }
44 }
45
46 - return {
46 + const elementType = {
47 $$typeof: REACT_FORWARD_REF_TYPE,
48 render,
49 };
50 + if (__DEV__) {
51 + let ownName;
52 + Object.defineProperty(elementType, 'displayName', {
53 + enumerable: false,
54 + configurable: true,
55 + get: function() {
56 + return ownName;
57 + },
58 + set: function(name) {
59 + ownName = name;
60 + if (render.displayName == null) {
61 + render.displayName = name;
62 + }
63 + },
64 + });
65 + }
66 + return elementType;
67 }
packages/react/src/ReactMemo.js
+18 -1
@@ -22,9 +22,26 @@ export function memo<Props>(
22 );
23 }
24 }
25 - return {
25 + const elementType = {
26 $$typeof: REACT_MEMO_TYPE,
27 type,
28 compare: compare === undefined ? null : compare,
29 };
30 + if (__DEV__) {
31 + let ownName;
32 + Object.defineProperty(elementType, 'displayName', {
33 + enumerable: false,
34 + configurable: true,
35 + get: function() {
36 + return ownName;
37 + },
38 + set: function(name) {
39 + ownName = name;
40 + if (type.displayName == null) {
41 + type.displayName = name;
42 + }
43 + },
44 + });
45 + }
46 + return elementType;
47 }
packages/react/src/__tests__/ReactContextValidator-test.js
+1 -3
@@ -690,9 +690,7 @@ describe('ReactContextValidator', () => {
690 );
691 }).toErrorDev(
692 'Warning: Failed prop type: The prop `dontPassToSeeErrorStack` is marked as required in `Validator`, but its value is `undefined`.\n' +
693 - ' in Validator (at **)\n' +
694 - ' in MyContextType.Consumer (at **)\n' +
695 - ' in MyContextType.Provider (at **)',
693 + ' in Validator (at **)',
694 );
695 });
696
packages/react/src/__tests__/ReactStrictMode-test.js
+2 -7
@@ -40,8 +40,7 @@ describe('ReactStrictMode', () => {
40 'Invalid ARIA attribute `ariaTypo`. ' +
41 'ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
42 ' in div (at **)\n' +
43 - ' in Foo (at **)\n' +
44 - ' in StrictMode (at **)',
43 + ' in Foo (at **)',
44 );
45 });
46
@@ -60,8 +59,7 @@ describe('ReactStrictMode', () => {
59 'Invalid ARIA attribute `ariaTypo`. ' +
60 'ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
61 ' in div (at **)\n' +
63 - ' in Foo (at **)\n' +
64 - ' in StrictMode (at **)',
62 + ' in Foo (at **)',
63 );
64 });
65
@@ -759,7 +757,6 @@ describe('string refs', () => {
757 'We recommend using useRef() or createRef() instead. ' +
758 'Learn more about using refs safely here: ' +
759 'https://fb.me/react-strict-mode-string-ref\n' +
762 - ' in StrictMode (at **)\n' +
760 ' in OuterComponent (at **)',
761 );
762
@@ -802,7 +799,6 @@ describe('string refs', () => {
799 'Learn more about using refs safely here: ' +
800 'https://fb.me/react-strict-mode-string-ref\n' +
801 ' in InnerComponent (at **)\n' +
805 - ' in StrictMode (at **)\n' +
802 ' in OuterComponent (at **)',
803 );
804
@@ -883,7 +879,6 @@ describe('context legacy', () => {
879 '\n\nLearn more about this warning here: ' +
880 'https://fb.me/react-legacy-context' +
881 '\n in LegacyContextProvider (at **)' +
886 - '\n in StrictMode (at **)' +
882 '\n in div (at **)' +
883 '\n in Root (at **)',
884 );
packages/react/src/__tests__/forwardRef-test.js
+28 -1
@@ -121,7 +121,7 @@ describe('forwardRef', () => {
121 ).toErrorDev(
122 'Warning: Failed prop type: The prop `required` is marked as required in ' +
123 '`ForwardRef(NamedFunction)`, but its value is `undefined`.\n' +
124 - ' in ForwardRef(NamedFunction) (at **)',
124 + ' in NamedFunction (at **)',
125 );
126 });
127
@@ -246,6 +246,33 @@ describe('forwardRef', () => {
246 );
247 });
248
249 + it('should honor a displayName in stacks if set on the inner function', () => {
250 + const Component = props => <div {...props} />;
251 +
252 + const inner = (props, ref) => <Component {...props} forwardedRef={ref} />;
253 + inner.displayName = 'Foo';
254 + const RefForwardingComponent = React.forwardRef(inner);
255 +
256 + RefForwardingComponent.propTypes = {
257 + optional: PropTypes.string,
258 + required: PropTypes.string.isRequired,
259 + };
260 +
261 + RefForwardingComponent.defaultProps = {
262 + optional: 'default',
263 + };
264 +
265 + const ref = React.createRef();
266 +
267 + expect(() =>
268 + ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
269 + ).toErrorDev(
270 + 'Warning: Failed prop type: The prop `required` is marked as required in ' +
271 + '`ForwardRef(Foo)`, but its value is `undefined`.\n' +
272 + ' in Foo (at **)',
273 + );
274 + });
275 +
276 it('should not bailout if forwardRef is not wrapped in memo', () => {
277 const Component = props => <div {...props} />;
278
packages/shared/ReactComponentStackFrame.js new
+142
@@ -0,0 +1,142 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {Source} from 'shared/ReactElementType';
11 +import type {LazyComponent} from 'react/src/ReactLazy';
12 +
13 +import {
14 + REACT_SUSPENSE_TYPE,
15 + REACT_SUSPENSE_LIST_TYPE,
16 + REACT_FORWARD_REF_TYPE,
17 + REACT_MEMO_TYPE,
18 + REACT_BLOCK_TYPE,
19 + REACT_LAZY_TYPE,
20 +} from 'shared/ReactSymbols';
21 +
22 +const BEFORE_SLASH_RE = /^(.*)[\\\/]/;
23 +
24 +function describeComponentFrame(
25 + name: null | string,
26 + source: void | null | Source,
27 + ownerName: null | string,
28 +) {
29 + let sourceInfo = '';
30 + if (__DEV__ && source) {
31 + const path = source.fileName;
32 + let fileName = path.replace(BEFORE_SLASH_RE, '');
33 + // In DEV, include code for a common special case:
34 + // prefer "folder/index.js" instead of just "index.js".
35 + if (/^index\./.test(fileName)) {
36 + const match = path.match(BEFORE_SLASH_RE);
37 + if (match) {
38 + const pathBeforeSlash = match[1];
39 + if (pathBeforeSlash) {
40 + const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, '');
41 + fileName = folderName + '/' + fileName;
42 + }
43 + }
44 + }
45 + sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')';
46 + } else if (ownerName) {
47 + sourceInfo = ' (created by ' + ownerName + ')';
48 + }
49 + return '\n in ' + (name || 'Unknown') + sourceInfo;
50 +}
51 +
52 +export function describeBuiltInComponentFrame(
53 + name: string,
54 + source: void | null | Source,
55 + ownerFn: void | null | Function,
56 +): string {
57 + let ownerName = null;
58 + if (__DEV__ && ownerFn) {
59 + ownerName = ownerFn.displayName || ownerFn.name || null;
60 + }
61 + return describeComponentFrame(name, source, ownerName);
62 +}
63 +
64 +export function describeClassComponentFrame(
65 + ctor: Function,
66 + source: void | null | Source,
67 + ownerFn: void | null | Function,
68 +): string {
69 + return describeFunctionComponentFrame(ctor, source, ownerFn);
70 +}
71 +
72 +export function describeFunctionComponentFrame(
73 + fn: Function,
74 + source: void | null | Source,
75 + ownerFn: void | null | Function,
76 +): string {
77 + if (!fn) {
78 + return '';
79 + }
80 + const name = fn.displayName || fn.name || null;
81 + let ownerName = null;
82 + if (__DEV__ && ownerFn) {
83 + ownerName = ownerFn.displayName || ownerFn.name || null;
84 + }
85 + return describeComponentFrame(name, source, ownerName);
86 +}
87 +
88 +function shouldConstruct(Component: Function) {
89 + const prototype = Component.prototype;
90 + return !!(prototype && prototype.isReactComponent);
91 +}
92 +
93 +export function describeUnknownElementTypeFrameInDEV(
94 + type: any,
95 + source: void | null | Source,
96 + ownerFn: void | null | Function,
97 +): string {
98 + if (!__DEV__) {
99 + return '';
100 + }
101 + if (type == null) {
102 + return '';
103 + }
104 + if (typeof type === 'function') {
105 + if (shouldConstruct(type)) {
106 + return describeClassComponentFrame(type, source, ownerFn);
107 + }
108 + return describeFunctionComponentFrame(type, source, ownerFn);
109 + }
110 + if (typeof type === 'string') {
111 + return describeBuiltInComponentFrame(type, source, ownerFn);
112 + }
113 + switch (type) {
114 + case REACT_SUSPENSE_TYPE:
115 + return describeBuiltInComponentFrame('Suspense', source, ownerFn);
116 + case REACT_SUSPENSE_LIST_TYPE:
117 + return describeBuiltInComponentFrame('SuspenseList', source, ownerFn);
118 + }
119 + if (typeof type === 'object') {
120 + switch (type.$$typeof) {
121 + case REACT_FORWARD_REF_TYPE:
122 + return describeFunctionComponentFrame(type.render, source, ownerFn);
123 + case REACT_MEMO_TYPE:
124 + return describeFunctionComponentFrame(type.type, source, ownerFn);
125 + case REACT_BLOCK_TYPE:
126 + return describeFunctionComponentFrame(type._render, source, ownerFn);
127 + case REACT_LAZY_TYPE: {
128 + const lazyComponent: LazyComponent<any, any> = (type: any);
129 + const payload = lazyComponent._payload;
130 + const init = lazyComponent._init;
131 + try {
132 + return describeUnknownElementTypeFrameInDEV(
133 + init(payload),
134 + source,
135 + ownerFn,
136 + );
137 + } catch (x) {}
138 + }
139 + }
140 + }
141 + return '';
142 +}
packages/shared/ReactFeatureFlags.js
+2
@@ -97,6 +97,8 @@ export const deferPassiveEffectCleanupDuringUnmount = false;
97 // a deprecated pattern we want to get rid of in the future
98 export const warnAboutSpreadingKeyToJSX = false;
99
100 +export const enableComponentStackLocations = false;
101 +
102 // Internal-only attempt to debug a React Native issue. See D20130868.
103 export const throwEarlyForMysteriousError = false;
104
packages/shared/describeComponentFrame.js deleted
-40
@@ -1,40 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -const BEFORE_SLASH_RE = /^(.*)[\\\/]/;
11 -
12 -export default function(
13 - name: null | string,
14 - source: any,
15 - ownerName: null | string,
16 -) {
17 - let sourceInfo = '';
18 - if (source) {
19 - const path = source.fileName;
20 - let fileName = path.replace(BEFORE_SLASH_RE, '');
21 - if (__DEV__) {
22 - // In DEV, include code for a common special case:
23 - // prefer "folder/index.js" instead of just "index.js".
24 - if (/^index\./.test(fileName)) {
25 - const match = path.match(BEFORE_SLASH_RE);
26 - if (match) {
27 - const pathBeforeSlash = match[1];
28 - if (pathBeforeSlash) {
29 - const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, '');
30 - fileName = folderName + '/' + fileName;
31 - }
32 - }
33 - }
34 - }
35 - sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')';
36 - } else if (ownerName) {
37 - sourceInfo = ' (created by ' + ownerName + ')';
38 - }
39 - return '\n in ' + (name || 'Unknown') + sourceInfo;
40 -}
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1
@@ -42,6 +42,7 @@ export const deferPassiveEffectCleanupDuringUnmount = false;
42 export const runAllPassiveEffectDestroysBeforeCreates = false;
43 export const enableModernEventSystem = false;
44 export const warnAboutSpreadingKeyToJSX = false;
45 +export const enableComponentStackLocations = false;
46 export const enableLegacyFBSupport = false;
47
48 // Internal-only attempt to debug a React Native issue. See D20130868.
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -41,6 +41,7 @@ export const deferPassiveEffectCleanupDuringUnmount = false;
41 export const runAllPassiveEffectDestroysBeforeCreates = false;
42 export const enableModernEventSystem = false;
43 export const warnAboutSpreadingKeyToJSX = false;
44 +export const enableComponentStackLocations = false;
45 export const enableLegacyFBSupport = false;
46
47 // Internal-only attempt to debug a React Native issue. See D20130868.
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -41,6 +41,7 @@ export const deferPassiveEffectCleanupDuringUnmount = false;
41 export const runAllPassiveEffectDestroysBeforeCreates = false;
42 export const enableModernEventSystem = false;
43 export const warnAboutSpreadingKeyToJSX = false;
44 +export const enableComponentStackLocations = false;
45 export const enableLegacyFBSupport = false;
46
47 // Internal-only attempt to debug a React Native issue. See D20130868.
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -41,6 +41,7 @@ export const deferPassiveEffectCleanupDuringUnmount = true;
41 export const runAllPassiveEffectDestroysBeforeCreates = true;
42 export const enableModernEventSystem = false;
43 export const warnAboutSpreadingKeyToJSX = false;
44 +export const enableComponentStackLocations = false;
45 export const enableLegacyFBSupport = false;
46
47 // Internal-only attempt to debug a React Native issue. See D20130868.
packages/shared/forks/ReactFeatureFlags.testing.js
+1
@@ -41,6 +41,7 @@ export const deferPassiveEffectCleanupDuringUnmount = false;
41 export const runAllPassiveEffectDestroysBeforeCreates = false;
42 export const enableModernEventSystem = false;
43 export const warnAboutSpreadingKeyToJSX = false;
44 +export const enableComponentStackLocations = false;
45 export const enableLegacyFBSupport = false;
46
47 // Internal-only attempt to debug a React Native issue. See D20130868.
packages/shared/forks/ReactFeatureFlags.testing.www.js
+1
@@ -41,6 +41,7 @@ export const deferPassiveEffectCleanupDuringUnmount = true;
41 export const runAllPassiveEffectDestroysBeforeCreates = true;
42 export const enableModernEventSystem = false;
43 export const warnAboutSpreadingKeyToJSX = false;
44 +export const enableComponentStackLocations = false;
45 export const enableLegacyFBSupport = !__EXPERIMENTAL__;
46
47 // Internal-only attempt to debug a React Native issue. See D20130868.
packages/shared/forks/ReactFeatureFlags.www-dynamic.js
+1
@@ -14,6 +14,7 @@
14 // with the __VARIANT__ set to `true`, and once set to `false`.
15
16 export const warnAboutSpreadingKeyToJSX = __VARIANT__;
17 +export const enableComponentStackLocations = __VARIANT__;
18 export const disableModulePatternComponents = __VARIANT__;
19 export const disableInputAttributeSyncing = __VARIANT__;
20
packages/shared/forks/ReactFeatureFlags.www.js
+1
@@ -21,6 +21,7 @@ export const {
21 enableTrustedTypesIntegration,
22 disableSchedulerTimeoutBasedOnReactExpirationTime,
23 warnAboutSpreadingKeyToJSX,
24 + enableComponentStackLocations,
25 replayFailedUnitOfWorkWithInvokeGuardedCallback,
26 enableModernEventSystem,
27 } = dynamicFeatureFlags;