From 2c406d8b49f75f42e1764ba309a8196ae89f1e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Wed, 29 Jan 2025 12:17:45 -0800 Subject: [PATCH] Remove logged errors for feature flags not implemented in native when skipNativeAPI is used (#49050) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/49050 Changelog: [internal] We added support for feature flags that don't have a native module definition so we could handle cases where the JS changes progressed faster than native ones, but we recently saw that when native catches up, the API starts logging an error through `console.error` about the native module method not being available. That's an expected result of this feature and it's when we can clean up the code in JS, so we shouldn't be logging errors in that case. This removes the error for them specifically. Reviewed By: elicwhite Differential Revision: D68843247 fbshipit-source-id: 730f3eba8c26959825cd9c3897f055a02a5f9591 --- .../templates/js/ReactNativeFeatureFlags.js-template.js | 2 +- .../src/private/featureflags/ReactNativeFeatureFlags.js | 6 +++--- .../private/featureflags/ReactNativeFeatureFlagsBase.js | 3 ++- .../__tests__/ReactNativeFeatureFlags-test.js | 9 +++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/react-native/scripts/featureflags/templates/js/ReactNativeFeatureFlags.js-template.js b/packages/react-native/scripts/featureflags/templates/js/ReactNativeFeatureFlags.js-template.js index 5bf488ba9fb9f2..96fd0417680aaf 100644 --- a/packages/react-native/scripts/featureflags/templates/js/ReactNativeFeatureFlags.js-template.js +++ b/packages/react-native/scripts/featureflags/templates/js/ReactNativeFeatureFlags.js-template.js @@ -75,7 +75,7 @@ ${Object.entries(definitions.common) */ export const ${flagName}: Getter<${typeof flagConfig.defaultValue}> = createNativeFlagGetter('${flagName}', ${JSON.stringify( flagConfig.defaultValue, - )});`, + )}${flagConfig.skipNativeAPI === true ? ', true' : ''});`, ) .join('\n')} diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 55d41655b3d005..1f40abdfca7378 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1292b8fff14cbf6ea3bffea28d0428bc>> + * @generated SignedSource<<3c609bd4ace6147f8f32af07a5e3cc05>> * @flow strict */ @@ -169,11 +169,11 @@ export const commonTestFlag: Getter = createNativeFlagGetter('commonTes /** * Common flag for testing (without native implementation). Do NOT modify. */ -export const commonTestFlagWithoutNativeImplementation: Getter = createNativeFlagGetter('commonTestFlagWithoutNativeImplementation', false); +export const commonTestFlagWithoutNativeImplementation: Getter = createNativeFlagGetter('commonTestFlagWithoutNativeImplementation', false, true); /** * The bridgeless architecture enables the event loop by default. This feature flag allows us to force disabling it in specific instances. */ -export const disableEventLoopOnBridgeless: Getter = createNativeFlagGetter('disableEventLoopOnBridgeless', false); +export const disableEventLoopOnBridgeless: Getter = createNativeFlagGetter('disableEventLoopOnBridgeless', false, true); /** * Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread */ diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js index 062f6c9d239a3f..9c3663cdfe61f1 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js @@ -62,12 +62,13 @@ type NativeFeatureFlags = $NonMaybeType; export function createNativeFlagGetter>( configName: K, defaultValue: ReturnType<$NonMaybeType>, + skipUnavailableNativeModuleError: boolean = false, ): Getter>> { return createGetter( configName, () => { const valueFromNative = NativeReactNativeFeatureFlags?.[configName]?.(); - if (valueFromNative == null) { + if (valueFromNative == null && !skipUnavailableNativeModuleError) { logUnavailableNativeModuleError(configName); } return valueFromNative; diff --git a/packages/react-native/src/private/featureflags/__tests__/ReactNativeFeatureFlags-test.js b/packages/react-native/src/private/featureflags/__tests__/ReactNativeFeatureFlags-test.js index cc1121b0b756a7..3a46809c65d874 100644 --- a/packages/react-native/src/private/featureflags/__tests__/ReactNativeFeatureFlags-test.js +++ b/packages/react-native/src/private/featureflags/__tests__/ReactNativeFeatureFlags-test.js @@ -26,6 +26,15 @@ describe('ReactNativeFeatureFlags', () => { ); }); + it('should provide default values for common flags and NOT log an error if the native module is NOT available and `skipNativeAPI` is used', () => { + const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags'); + expect( + ReactNativeFeatureFlags.commonTestFlagWithoutNativeImplementation(), + ).toBe(false); + + expect(console.error).toHaveBeenCalledTimes(0); + }); + it('should provide default values for common flags and log an error if the method in the native module is NOT available', () => { jest.doMock('../specs/NativeReactNativeFeatureFlags', () => ({ __esModule: true,