From 113785492534289949777461dd88de871ed7ad70 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 3 Aug 2021 20:40:05 -0400 Subject: [PATCH] Import dynamic RN flags from external module Internal feature flags that we wish to control with a GK can now be imported from an external module, which I've called "ReactNativeInternalFeatureFlags". We'll need to add this module to the downstream repo. We can't yet use this in our tests, because we don't have a test configuration that runs against the React Native feature flags fork. We should set up that up the same way we did for www. --- .../ReactFeatureFlags.native-fb-dynamic.js | 29 +++++++++++++++++++ .../forks/ReactFeatureFlags.native-fb.js | 10 +++++-- scripts/flow/config/flowconfig | 1 + scripts/flow/xplat.js | 12 ++++++++ scripts/rollup/bundles.js | 23 ++++++++++----- scripts/rollup/modules.js | 2 ++ 6 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js create mode 100644 scripts/flow/xplat.js diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js new file mode 100644 index 0000000000000..63f75e83b7656 --- /dev/null +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + */ + +import typeof * as ExportsType from './ReactFeatureFlags.native-fb-dynamic'; +import typeof * as DynamicFlagsType from 'ReactNativeInternalFeatureFlags'; + +// In xplat, these flags are controlled by GKs. Because most GKs have some +// population running in either mode, we should run our tests that way, too, +// +// Use __VARIANT__ to simulate a GK. The tests will be run twice: once +// with the __VARIANT__ set to `true`, and once set to `false`. +// +// TODO: __VARIANT__ isn't supported for React Native flags yet. You can set the +// flag here but it won't be set to `true` in any of our test runs. Need to +// update the test configuration. + +export const enablePersistentOffscreenHostContainer = __VARIANT__; + +// Flow magic to verify the exports of this file match the original version. +// eslint-disable-next-line no-unused-vars +type Check<_X, Y: _X, X: Y = _X> = null; +// eslint-disable-next-line no-unused-expressions +(null: Check); diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 8d0a2256ec7d2..f6ab60d3ed642 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -10,6 +10,14 @@ import typeof * as FeatureFlagsType from 'shared/ReactFeatureFlags'; import typeof * as ExportsType from './ReactFeatureFlags.native-fb'; +// Re-export dynamic flags from the internal module. Intentionally using * +// because this import is compiled to a `require` call. +import * as dynamicFlags from 'ReactNativeInternalFeatureFlags'; + +// We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. +export const {enablePersistentOffscreenHostContainer} = dynamicFlags; + // The rest of the flags are static for better dead code elimination. export const enableDebugTracing = false; export const enableSchedulingProfiler = false; @@ -60,8 +68,6 @@ export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = true; -// TODO: Import this from internal ReactNativeFeatureFlags instead -export const enablePersistentOffscreenHostContainer = __EXPERIMENTAL__; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/scripts/flow/config/flowconfig b/scripts/flow/config/flowconfig index ada7f2207be5c..2ace94c2d7cba 100644 --- a/scripts/flow/config/flowconfig +++ b/scripts/flow/config/flowconfig @@ -34,6 +34,7 @@ ./scripts/flow/react-devtools.js ./scripts/flow/react-native-host-hooks.js ./scripts/flow/react-relay-hooks.js +./scripts/flow/xplat.js [lints] untyped-type-import=error diff --git a/scripts/flow/xplat.js b/scripts/flow/xplat.js new file mode 100644 index 0000000000000..c013af3e125d8 --- /dev/null +++ b/scripts/flow/xplat.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +declare module 'ReactNativeInternalFeatureFlags' { + declare export var enablePersistentOffscreenHostContainer: boolean; +} diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index fb64c0e6e07f4..54c0552ba5649 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -79,7 +79,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'react', global: 'React', - externals: [], + externals: ['ReactNativeInternalFeatureFlags'], }, /******* Isomorphic Shared Subset *******/ @@ -105,7 +105,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'react/jsx-runtime', global: 'JSXRuntime', - externals: ['react'], + externals: ['react', 'ReactNativeInternalFeatureFlags'], }, /******* React JSX DEV Runtime *******/ @@ -124,7 +124,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'react/jsx-dev-runtime', global: 'JSXDEVRuntime', - externals: ['react'], + externals: ['react', 'ReactNativeInternalFeatureFlags'], }, /******* React Fetch Browser (experimental, new) *******/ @@ -372,6 +372,7 @@ const bundles = [ 'react', 'ReactFlightNativeRelayServerIntegration', 'JSResourceReferenceImpl', + 'ReactNativeInternalFeatureFlags', ], }, @@ -385,6 +386,7 @@ const bundles = [ 'react', 'ReactFlightNativeRelayClientIntegration', 'JSResourceReferenceImpl', + 'ReactNativeInternalFeatureFlags', ], }, @@ -432,7 +434,7 @@ const bundles = [ moduleType: RENDERER, entry: 'react-native-renderer', global: 'ReactNativeRenderer', - externals: ['react-native'], + externals: ['react-native', 'ReactNativeInternalFeatureFlags'], babel: opts => Object.assign({}, opts, { plugins: opts.plugins.concat([ @@ -462,7 +464,7 @@ const bundles = [ moduleType: RENDERER, entry: 'react-native-renderer/fabric', global: 'ReactFabric', - externals: ['react-native'], + externals: ['react-native', 'ReactNativeInternalFeatureFlags'], babel: opts => Object.assign({}, opts, { plugins: opts.plugins.concat([ @@ -499,7 +501,12 @@ const bundles = [ moduleType: RENDERER, entry: 'react-test-renderer', global: 'ReactTestRenderer', - externals: ['react', 'scheduler', 'scheduler/unstable_mock'], + externals: [ + 'react', + 'scheduler', + 'scheduler/unstable_mock', + 'ReactNativeInternalFeatureFlags', + ], babel: opts => Object.assign({}, opts, { plugins: opts.plugins.concat([ @@ -692,7 +699,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'scheduler', global: 'Scheduler', - externals: [], + externals: ['ReactNativeInternalFeatureFlags'], }, /******* React Scheduler Mock (experimental) *******/ @@ -710,7 +717,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'scheduler/unstable_mock', global: 'SchedulerMock', - externals: [], + externals: ['ReactNativeInternalFeatureFlags'], }, /******* React Scheduler Post Task (experimental) *******/ diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index b56f4231e2ef0..2461e28850cc0 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -21,6 +21,7 @@ const importSideEffects = Object.freeze({ 'react-fetch/node': HAS_NO_SIDE_EFFECTS_ON_IMPORT, 'react-dom': HAS_NO_SIDE_EFFECTS_ON_IMPORT, url: HAS_NO_SIDE_EFFECTS_ON_IMPORT, + ReactNativeInternalFeatureFlags: HAS_NO_SIDE_EFFECTS_ON_IMPORT, }); // Bundles exporting globals that other modules rely on. @@ -31,6 +32,7 @@ const knownGlobals = Object.freeze({ 'react-interactions/events/tap': 'ReactEventsTap', scheduler: 'Scheduler', 'scheduler/unstable_mock': 'SchedulerMock', + ReactNativeInternalFeatureFlags: 'ReactNativeInternalFeatureFlags', }); // Given ['react'] in bundle externals, returns { 'react': 'React' }.