From a4964987dc140526702e996223fe7ee293def8ac Mon Sep 17 00:00:00 2001 From: Noah Lemen Date: Wed, 11 Dec 2024 12:00:25 -0500 Subject: [PATCH] Make enableOwnerStacks dynamic (#31661) following up on https://github.com/facebook/react/pull/31287, fixing tests --------- Co-authored-by: Rick Hanlon --- packages/react/index.fb.js | 10 ++ packages/react/src/ReactServer.fb.js | 9 ++ .../src/__tests__/ReactStrictMode-test.js | 95 ++++++++++++------- .../createReactClassIntegration-test.js | 9 +- .../ReactFeatureFlags.native-fb-dynamic.js | 1 + .../forks/ReactFeatureFlags.native-fb.js | 2 +- .../forks/ReactFeatureFlags.www-dynamic.js | 1 + .../shared/forks/ReactFeatureFlags.www.js | 2 +- 8 files changed, 92 insertions(+), 37 deletions(-) diff --git a/packages/react/index.fb.js b/packages/react/index.fb.js index 7892f31dd4757..4764281481dbb 100644 --- a/packages/react/index.fb.js +++ b/packages/react/index.fb.js @@ -7,6 +7,8 @@ * @flow */ +import {enableOwnerStacks} from 'shared/ReactFeatureFlags'; +import {captureOwnerStack as captureOwnerStackImpl} from './src/ReactClient'; export { __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, __COMPILER_RUNTIME, @@ -68,3 +70,11 @@ export {useMemoCache as unstable_useMemoCache} from './src/ReactHooks'; // export to match the name of the OSS function typically exported from // react/compiler-runtime export {useMemoCache as c} from './src/ReactHooks'; + +// Only export captureOwnerStack in development. +let captureOwnerStack: ?() => null | string; +if (__DEV__ && enableOwnerStacks) { + captureOwnerStack = captureOwnerStackImpl; +} + +export {captureOwnerStack}; diff --git a/packages/react/src/ReactServer.fb.js b/packages/react/src/ReactServer.fb.js index d6702023e4741..fe6260a799a2c 100644 --- a/packages/react/src/ReactServer.fb.js +++ b/packages/react/src/ReactServer.fb.js @@ -10,6 +10,8 @@ export {default as __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE} from './ReactSharedInternalsServer'; import {forEach, map, count, toArray, only} from './ReactChildren'; +import {enableOwnerStacks} from 'shared/ReactFeatureFlags'; +import {captureOwnerStack as captureOwnerStackImpl} from './ReactOwnerStack'; import { REACT_FRAGMENT_TYPE, REACT_PROFILER_TYPE, @@ -37,6 +39,12 @@ const Children = { only, }; +// Only export captureOwnerStack if the flag is on, to support feature detection. +let captureOwnerStack: ?() => null | string; +if (__DEV__ && enableOwnerStacks) { + captureOwnerStack = captureOwnerStackImpl; +} + export { Children, REACT_FRAGMENT_TYPE as Fragment, @@ -57,4 +65,5 @@ export { useDebugValue, useMemo, version, + captureOwnerStack, // DEV-only }; diff --git a/packages/react/src/__tests__/ReactStrictMode-test.js b/packages/react/src/__tests__/ReactStrictMode-test.js index 97fcc1ec8c4ce..db60674ba64bf 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.js @@ -1028,40 +1028,67 @@ describe('context legacy', () => { root.render(); }); - assertConsoleErrorDev([ - 'LegacyContextProvider uses the legacy childContextTypes API ' + - 'which will soon be removed. Use React.createContext() instead. ' + - '(https://react.dev/link/legacy-context)' + - '\n in LegacyContextProvider (at **)' + - '\n in div (at **)' + - '\n in Root (at **)', - 'LegacyContextConsumer uses the legacy contextTypes API which ' + - 'will soon be removed. Use React.createContext() with static ' + - 'contextType instead. (https://react.dev/link/legacy-context)' + - '\n in LegacyContextConsumer (at **)' + - '\n in div (at **)' + - '\n in LegacyContextProvider (at **)' + - '\n in div (at **)' + - '\n in Root (at **)', - 'FunctionalLegacyContextConsumer uses the legacy contextTypes ' + - 'API which will be removed soon. Use React.createContext() ' + - 'with React.useContext() instead. (https://react.dev/link/legacy-context)' + - '\n in FunctionalLegacyContextConsumer (at **)' + - '\n in div (at **)' + - '\n in LegacyContextProvider (at **)' + - '\n in div (at **)' + - '\n in Root (at **)', - 'Legacy context API has been detected within a strict-mode tree.' + - '\n\nThe old API will be supported in all 16.x releases, but applications ' + - 'using it should migrate to the new version.' + - '\n\nPlease update the following components: ' + - 'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' + - '\n\nLearn more about this warning here: ' + - 'https://react.dev/link/legacy-context' + - '\n in LegacyContextProvider (at **)' + - '\n in div (at **)' + - '\n in Root (at **)', - ]); + if (gate(flags => flags.enableOwnerStacks)) { + assertConsoleErrorDev([ + 'LegacyContextProvider uses the legacy childContextTypes API ' + + 'which will soon be removed. Use React.createContext() instead. ' + + '(https://react.dev/link/legacy-context)' + + '\n in Root (at **)', + 'LegacyContextConsumer uses the legacy contextTypes API which ' + + 'will soon be removed. Use React.createContext() with static ' + + 'contextType instead. (https://react.dev/link/legacy-context)' + + '\n in LegacyContextProvider (at **)' + + '\n in Root (at **)', + 'FunctionalLegacyContextConsumer uses the legacy contextTypes ' + + 'API which will be removed soon. Use React.createContext() ' + + 'with React.useContext() instead. (https://react.dev/link/legacy-context)' + + '\n in LegacyContextProvider (at **)' + + '\n in Root (at **)', + 'Legacy context API has been detected within a strict-mode tree.' + + '\n\nThe old API will be supported in all 16.x releases, but applications ' + + 'using it should migrate to the new version.' + + '\n\nPlease update the following components: ' + + 'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' + + '\n\nLearn more about this warning here: ' + + 'https://react.dev/link/legacy-context' + + '\n in Root (at **)', + ]); + } else { + assertConsoleErrorDev([ + 'LegacyContextProvider uses the legacy childContextTypes API ' + + 'which will soon be removed. Use React.createContext() instead. ' + + '(https://react.dev/link/legacy-context)' + + '\n in LegacyContextProvider (at **)' + + '\n in div (at **)' + + '\n in Root (at **)', + 'LegacyContextConsumer uses the legacy contextTypes API which ' + + 'will soon be removed. Use React.createContext() with static ' + + 'contextType instead. (https://react.dev/link/legacy-context)' + + '\n in LegacyContextConsumer (at **)' + + '\n in div (at **)' + + '\n in LegacyContextProvider (at **)' + + '\n in div (at **)' + + '\n in Root (at **)', + 'FunctionalLegacyContextConsumer uses the legacy contextTypes ' + + 'API which will be removed soon. Use React.createContext() ' + + 'with React.useContext() instead. (https://react.dev/link/legacy-context)' + + '\n in FunctionalLegacyContextConsumer (at **)' + + '\n in div (at **)' + + '\n in LegacyContextProvider (at **)' + + '\n in div (at **)' + + '\n in Root (at **)', + 'Legacy context API has been detected within a strict-mode tree.' + + '\n\nThe old API will be supported in all 16.x releases, but applications ' + + 'using it should migrate to the new version.' + + '\n\nPlease update the following components: ' + + 'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' + + '\n\nLearn more about this warning here: ' + + 'https://react.dev/link/legacy-context' + + '\n in LegacyContextProvider (at **)' + + '\n in div (at **)' + + '\n in Root (at **)', + ]); + } // Dedupe await act(() => { diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.js b/packages/react/src/__tests__/createReactClassIntegration-test.js index 811d897e859e7..4aabc11b52e8d 100644 --- a/packages/react/src/__tests__/createReactClassIntegration-test.js +++ b/packages/react/src/__tests__/createReactClassIntegration-test.js @@ -338,7 +338,14 @@ describe('create-react-class-integration', () => { root.render(); }); assertConsoleErrorDev([ - 'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.', + gate(flags => + flags.enableOwnerStacks + ? [ + 'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.', + {withoutStack: true}, + ] + : 'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.', + ), 'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.', ]); expect(container.firstChild.className).toBe('foo'); diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index 832838313095c..fc9bed7cc056f 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -26,3 +26,4 @@ export const passChildrenWhenCloningPersistedNodes = __VARIANT__; export const enableFabricCompleteRootInCommitPhase = __VARIANT__; export const enableSiblingPrerendering = __VARIANT__; export const enableUseResourceEffectHook = __VARIANT__; +export const enableOwnerStacks = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index defa7cd330d7f..58ae9c4fffe41 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -28,6 +28,7 @@ export const { enableUseResourceEffectHook, passChildrenWhenCloningPersistedNodes, enableSiblingPrerendering, + enableOwnerStacks, } = dynamicFlags; // The rest of the flags are static for better dead code elimination. @@ -67,7 +68,6 @@ export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; export const enableNoCloningMemoCache = false; -export const enableOwnerStacks = false; export const enablePostpone = false; export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index db38e0e1fdcba..7c28c76fb1392 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -27,6 +27,7 @@ export const enableRetryLaneExpiration = __VARIANT__; export const enableTransitionTracing = __VARIANT__; export const favorSafetyOverHydrationPerf = __VARIANT__; export const renameElementSymbol = __VARIANT__; +export const enableOwnerStacks = __VARIANT__; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 8ddbf3dd7c519..da97bbc212876 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -37,6 +37,7 @@ export const { retryLaneExpirationMs, syncLaneExpirationMs, transitionLaneExpirationMs, + enableOwnerStacks, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build. @@ -121,7 +122,6 @@ export const useModernStrictMode = true; export const disableLegacyMode = true; -export const enableOwnerStacks = false; export const enableShallowPropDiffing = false; // Flow magic to verify the exports of this file match the original version.