Skip to content

Commit 98dc7fb

Browse files
committed
Export captureOwnerStacks only in DEV "react" builds
Only with the enableOwnerStacks flag (which is not on in www).
1 parent f3e09d6 commit 98dc7fb

14 files changed

+380
-12
lines changed

packages/react-reconciler/src/ReactCurrentFiber.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export function getCurrentParentStackInDev(): string {
4444
return '';
4545
}
4646

47-
function getCurrentFiberStackInDev(stack: Error): string {
47+
function getCurrentFiberStackInDev(stack: null | Error): string {
4848
if (__DEV__) {
4949
if (current === null) {
5050
return '';
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and 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+
* @emails react-core
8+
* @jest-environment node
9+
*/
10+
'use strict';
11+
12+
let React;
13+
let ReactNoop;
14+
let act;
15+
16+
describe('ReactOwnerStacks', () => {
17+
beforeEach(function () {
18+
jest.resetModules();
19+
20+
React = require('react');
21+
ReactNoop = require('react-noop-renderer');
22+
act = require('internal-test-utils').act;
23+
});
24+
25+
function normalizeCodeLocInfo(str) {
26+
return (
27+
str &&
28+
str.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function (m, name) {
29+
return '\n in ' + name + ' (at **)';
30+
})
31+
);
32+
}
33+
34+
// @gate __DEV__ && enableOwnerStacks
35+
it('can get the component owner stacks during rendering in dev', async () => {
36+
let stack;
37+
38+
function Foo() {
39+
return <Bar />;
40+
}
41+
function Bar() {
42+
return (
43+
<div>
44+
<Baz />
45+
</div>
46+
);
47+
}
48+
function Baz() {
49+
stack = React.captureOwnerStack();
50+
return <span>hi</span>;
51+
}
52+
53+
await act(() => {
54+
ReactNoop.render(
55+
<div>
56+
<Foo />
57+
</div>,
58+
);
59+
});
60+
61+
expect(normalizeCodeLocInfo(stack)).toBe(
62+
'\n in Bar (at **)' + '\n in Foo (at **)',
63+
);
64+
});
65+
});

packages/react-test-renderer/src/ReactTestRenderer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
disableLegacyMode,
6262
} from 'shared/ReactFeatureFlags';
6363

64+
// $FlowFixMe[prop-missing]: This is only in the development export.
6465
const act = React.act;
6566

6667
// TODO: Remove from public bundle

packages/react/index.development.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and 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+
// Keep in sync with https://github.com/facebook/flow/blob/main/lib/react.js
11+
export type ComponentType<-P> = React$ComponentType<P>;
12+
export type AbstractComponent<
13+
-Config,
14+
+Instance = mixed,
15+
> = React$AbstractComponent<Config, Instance>;
16+
export type ElementType = React$ElementType;
17+
export type Element<+C> = React$Element<C>;
18+
export type Key = React$Key;
19+
export type Ref<C> = React$Ref<C>;
20+
export type Node = React$Node;
21+
export type Context<T> = React$Context<T>;
22+
export type Portal = React$Portal;
23+
export type ElementProps<C> = React$ElementProps<C>;
24+
export type ElementConfig<C> = React$ElementConfig<C>;
25+
export type ElementRef<C> = React$ElementRef<C>;
26+
export type Config<Props, DefaultProps> = React$Config<Props, DefaultProps>;
27+
export type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T;
28+
29+
// Export all exports so that they're available in tests.
30+
// We can't use export * from in Flow for some reason.
31+
export {
32+
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
33+
Children,
34+
Component,
35+
Fragment,
36+
Profiler,
37+
PureComponent,
38+
StrictMode,
39+
Suspense,
40+
cloneElement,
41+
createContext,
42+
createElement,
43+
createRef,
44+
use,
45+
forwardRef,
46+
isValidElement,
47+
lazy,
48+
memo,
49+
cache,
50+
startTransition,
51+
unstable_DebugTracingMode,
52+
unstable_LegacyHidden,
53+
unstable_Activity,
54+
unstable_Scope,
55+
unstable_SuspenseList,
56+
unstable_TracingMarker,
57+
unstable_getCacheForType,
58+
unstable_useCacheRefresh,
59+
useId,
60+
useCallback,
61+
useContext,
62+
useDebugValue,
63+
useDeferredValue,
64+
useEffect,
65+
experimental_useEffectEvent,
66+
useImperativeHandle,
67+
useInsertionEffect,
68+
useLayoutEffect,
69+
useMemo,
70+
useOptimistic,
71+
useSyncExternalStore,
72+
useReducer,
73+
useRef,
74+
useState,
75+
useTransition,
76+
useActionState,
77+
version,
78+
act, // DEV-only
79+
captureOwnerStack, // DEV-only
80+
} from './src/ReactClient';
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and 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+
export {
11+
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
12+
Children,
13+
Component,
14+
Fragment,
15+
Profiler,
16+
PureComponent,
17+
StrictMode,
18+
Suspense,
19+
cloneElement,
20+
createContext,
21+
createElement,
22+
createRef,
23+
use,
24+
forwardRef,
25+
isValidElement,
26+
lazy,
27+
memo,
28+
cache,
29+
startTransition,
30+
unstable_DebugTracingMode,
31+
unstable_Activity,
32+
unstable_postpone,
33+
unstable_getCacheForType,
34+
unstable_SuspenseList,
35+
unstable_useCacheRefresh,
36+
useId,
37+
useCallback,
38+
useContext,
39+
useDebugValue,
40+
useDeferredValue,
41+
useEffect,
42+
experimental_useEffectEvent,
43+
useImperativeHandle,
44+
useInsertionEffect,
45+
useLayoutEffect,
46+
useMemo,
47+
useOptimistic,
48+
useReducer,
49+
useRef,
50+
useState,
51+
useSyncExternalStore,
52+
useTransition,
53+
useActionState,
54+
version,
55+
act, // DEV-only
56+
captureOwnerStack, // DEV-only
57+
} from './src/ReactClient';
58+
59+
import {useOptimistic} from './src/ReactClient';
60+
61+
export function experimental_useOptimistic<S, A>(
62+
passthrough: S,
63+
reducer: ?(S, A) => S,
64+
): [S, (A) => void] {
65+
if (__DEV__) {
66+
console.error(
67+
'useOptimistic is now in canary. Remove the experimental_ prefix. ' +
68+
'The prefixed alias will be removed in an upcoming release.',
69+
);
70+
}
71+
return useOptimistic(passthrough, reducer);
72+
}

packages/react/index.experimental.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
export {
1111
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
12-
act,
1312
Children,
1413
Component,
1514
Fragment,

packages/react/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T;
3030
// We can't use export * from in Flow for some reason.
3131
export {
3232
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
33-
act,
3433
Children,
3534
Component,
3635
Fragment,

packages/react/src/ReactClient.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
import ReactSharedInternals from './ReactSharedInternalsClient';
6262
import {startTransition} from './ReactStartTransition';
6363
import {act} from './ReactAct';
64+
import {captureOwnerStack} from './ReactOwnerStack';
6465

6566
const Children = {
6667
map,
@@ -121,5 +122,6 @@ export {
121122
// enableTransitionTracing
122123
REACT_TRACING_MARKER_TYPE as unstable_TracingMarker,
123124
useId,
124-
act,
125+
act, // DEV-only
126+
captureOwnerStack, // DEV-only
125127
};

packages/react/src/ReactOwnerStack.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Copyright (c) Meta Platforms, 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 {enableOwnerStacks} from 'shared/ReactFeatureFlags';
11+
import ReactSharedInternals from 'shared/ReactSharedInternals';
12+
13+
export function captureOwnerStack(): null | string {
14+
if (!enableOwnerStacks || !__DEV__) {
15+
return null;
16+
}
17+
const getCurrentStack = ReactSharedInternals.getCurrentStack;
18+
if (getCurrentStack === null) {
19+
return null;
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);
24+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and 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+
export {default as __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE} from './ReactSharedInternalsServer';
11+
12+
import {forEach, map, count, toArray, only} from './ReactChildren';
13+
import {
14+
REACT_FRAGMENT_TYPE,
15+
REACT_PROFILER_TYPE,
16+
REACT_STRICT_MODE_TYPE,
17+
REACT_SUSPENSE_TYPE,
18+
REACT_DEBUG_TRACING_MODE_TYPE,
19+
} from 'shared/ReactSymbols';
20+
import {
21+
cloneElement,
22+
createElement,
23+
isValidElement,
24+
} from './jsx/ReactJSXElement';
25+
import {createRef} from './ReactCreateRef';
26+
import {
27+
use,
28+
useId,
29+
useCallback,
30+
useDebugValue,
31+
useMemo,
32+
useActionState,
33+
getCacheForType,
34+
} from './ReactHooks';
35+
import {forwardRef} from './ReactForwardRef';
36+
import {lazy} from './ReactLazy';
37+
import {memo} from './ReactMemo';
38+
import {cache} from './ReactCacheServer';
39+
import {startTransition} from './ReactStartTransition';
40+
import {postpone} from './ReactPostpone';
41+
import {captureOwnerStack} from './ReactOwnerStack';
42+
import version from 'shared/ReactVersion';
43+
44+
const Children = {
45+
map,
46+
forEach,
47+
count,
48+
toArray,
49+
only,
50+
};
51+
52+
// These are server-only
53+
export {
54+
taintUniqueValue as experimental_taintUniqueValue,
55+
taintObjectReference as experimental_taintObjectReference,
56+
} from './ReactTaint';
57+
58+
export {
59+
Children,
60+
REACT_FRAGMENT_TYPE as Fragment,
61+
REACT_PROFILER_TYPE as Profiler,
62+
REACT_STRICT_MODE_TYPE as StrictMode,
63+
REACT_SUSPENSE_TYPE as Suspense,
64+
cloneElement,
65+
createElement,
66+
createRef,
67+
use,
68+
forwardRef,
69+
isValidElement,
70+
lazy,
71+
memo,
72+
cache,
73+
startTransition,
74+
REACT_DEBUG_TRACING_MODE_TYPE as unstable_DebugTracingMode,
75+
REACT_SUSPENSE_TYPE as unstable_SuspenseList,
76+
getCacheForType as unstable_getCacheForType,
77+
postpone as unstable_postpone,
78+
useId,
79+
useCallback,
80+
useDebugValue,
81+
useMemo,
82+
useActionState,
83+
version,
84+
captureOwnerStack, // DEV-only
85+
};

packages/react/src/ReactSharedInternalsClient.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export type SharedStateClient = {
3535
thrownErrors: Array<mixed>,
3636

3737
// ReactDebugCurrentFrame
38-
getCurrentStack: null | ((stack: Error) => string),
38+
getCurrentStack: null | ((stack: null | Error) => string),
3939
};
4040

4141
export type RendererTask = boolean => RendererTask | null;
@@ -56,7 +56,7 @@ if (__DEV__) {
5656
// Stack implementation injected by the current renderer.
5757
ReactSharedInternals.getCurrentStack = (null:
5858
| null
59-
| ((stack: Error) => string));
59+
| ((stack: null | Error) => string));
6060
}
6161

6262
export default ReactSharedInternals;

0 commit comments

Comments
 (0)