diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h index f5e12f7227e525..c7cdd4943644ad 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h @@ -16,6 +16,9 @@ NS_ASSUME_NONNULL_BEGIN */ @interface RCTDefaultReactNativeFactoryDelegate : UIResponder + +- (nonnull NSArray *)getModuleNames; + @end NS_ASSUME_NONNULL_END diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm index 07562f178eb876..0f30529b4e674d 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm @@ -129,6 +129,13 @@ - (Class)getModuleClassFromName:(const char *)name return nullptr; } +- (nonnull NSArray *)getModuleNames{ + if([dependencyProvider respondsToSelector:@selector(moduleNames)]) { + return [dependencyProvider moduleNames]; + } + return @[]; +} + - (id)getModuleInstanceFromClass:(Class)moduleClass { return nullptr; diff --git a/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h b/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h index ddc412b0f71b91..706ae4044830ba 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h +++ b/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h @@ -26,6 +26,9 @@ NS_ASSUME_NONNULL_BEGIN - (nonnull NSDictionary> *)moduleProviders; +@optional +- (nonnull NSArray *)moduleNames; + @end NS_ASSUME_NONNULL_END diff --git a/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm index 9d5a45787af022..c4e08f5602557a 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm @@ -141,6 +141,13 @@ - (BOOL)bridgelessEnabled #pragma mark - RCTTurboModuleManagerDelegate +- (nonnull NSArray *)getModuleNames{ + if ([_delegate respondsToSelector:@selector(getModuleNames)]) { + return [_delegate getModuleNames]; + } + return @[]; +} + - (Class)getModuleClassFromName:(const char *)name { #if RN_DISABLE_OSS_PLUGIN_HEADER diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index 1c944cfdb449d5..cfe0dfbb5927a8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -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<<2294f3350aca0f19862f8cfdbe9479b6>> + * @generated SignedSource<<7c5701ed1e7ddafa497364e72afbbbe2>> */ /** @@ -318,6 +318,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun hideOffscreenVirtualViewsOnIOS(): Boolean = accessor.hideOffscreenVirtualViewsOnIOS() + /** + * Enables creating Module Holders for TurboModules before the JS Runtime is started, iOS only. Android already creates them early. + */ + @JvmStatic + public fun iosEarlyTurboModuleDiscovery(): Boolean = accessor.iosEarlyTurboModuleDiscovery() + /** * Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index 86efa711dbee61..a3f43d36813ced 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -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<<9f50b2fc5f4aad27e6cd8ecbde3d791a>> + * @generated SignedSource<<4e4dc5cc02194f3c632c49bb11f50be5>> */ /** @@ -68,6 +68,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var fuseboxEnabledReleaseCache: Boolean? = null private var fuseboxNetworkInspectionEnabledCache: Boolean? = null private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null + private var iosEarlyTurboModuleDiscoveryCache: Boolean? = null private var perfMonitorV2EnabledCache: Boolean? = null private var preparedTextCacheSizeCache: Double? = null private var preventShadowTreeCommitExhaustionCache: Boolean? = null @@ -521,6 +522,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun iosEarlyTurboModuleDiscovery(): Boolean { + var cached = iosEarlyTurboModuleDiscoveryCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.iosEarlyTurboModuleDiscovery() + iosEarlyTurboModuleDiscoveryCache = cached + } + return cached + } + override fun perfMonitorV2Enabled(): Boolean { var cached = perfMonitorV2EnabledCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 78807ec46d74e0..a9a22a0b61cb40 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -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<<27b8c102b60eadcf284fd3c156a037aa>> + * @generated SignedSource<<62beb45b5693fbdc4ff6b64e7f9b8898>> */ /** @@ -124,6 +124,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun hideOffscreenVirtualViewsOnIOS(): Boolean + @DoNotStrip @JvmStatic public external fun iosEarlyTurboModuleDiscovery(): Boolean + @DoNotStrip @JvmStatic public external fun perfMonitorV2Enabled(): Boolean @DoNotStrip @JvmStatic public external fun preparedTextCacheSize(): Double diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index d0a00d655c3407..afe309784ecbfe 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -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<<9583365cd9d7786ee9be03ff34b0766f>> + * @generated SignedSource<<47f42b3f088e12eb24ad4343d8275d55>> */ /** @@ -119,6 +119,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun hideOffscreenVirtualViewsOnIOS(): Boolean = false + override fun iosEarlyTurboModuleDiscovery(): Boolean = false + override fun perfMonitorV2Enabled(): Boolean = false override fun preparedTextCacheSize(): Double = 200.0 diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 5db38a867a2355..1308edc3bee24c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -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<<8bcbcc20f92faf4c50c093fac701dfa2>> + * @generated SignedSource<> */ /** @@ -72,6 +72,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var fuseboxEnabledReleaseCache: Boolean? = null private var fuseboxNetworkInspectionEnabledCache: Boolean? = null private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null + private var iosEarlyTurboModuleDiscoveryCache: Boolean? = null private var perfMonitorV2EnabledCache: Boolean? = null private var preparedTextCacheSizeCache: Double? = null private var preventShadowTreeCommitExhaustionCache: Boolean? = null @@ -573,6 +574,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun iosEarlyTurboModuleDiscovery(): Boolean { + var cached = iosEarlyTurboModuleDiscoveryCache + if (cached == null) { + cached = currentProvider.iosEarlyTurboModuleDiscovery() + accessedFeatureFlags.add("iosEarlyTurboModuleDiscovery") + iosEarlyTurboModuleDiscoveryCache = cached + } + return cached + } + override fun perfMonitorV2Enabled(): Boolean { var cached = perfMonitorV2EnabledCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 6bdae86b22bf2d..dd2d1e9d42e6c5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -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<<8a2403250a16c2b2b573fc05db6e4768>> + * @generated SignedSource<> */ /** @@ -119,6 +119,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun hideOffscreenVirtualViewsOnIOS(): Boolean + @DoNotStrip public fun iosEarlyTurboModuleDiscovery(): Boolean + @DoNotStrip public fun perfMonitorV2Enabled(): Boolean @DoNotStrip public fun preparedTextCacheSize(): Double diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index a9a3cdc5bb68fa..743e6f3eef12e3 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -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<<72694e8b935e15e4b826a0174fd0c23f>> + * @generated SignedSource<<14a636939fc8f8030580ae7eb91a68b2>> */ /** @@ -327,6 +327,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool iosEarlyTurboModuleDiscovery() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("iosEarlyTurboModuleDiscovery"); + return method(javaProvider_); + } + bool perfMonitorV2Enabled() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("perfMonitorV2Enabled"); @@ -691,6 +697,11 @@ bool JReactNativeFeatureFlagsCxxInterop::hideOffscreenVirtualViewsOnIOS( return ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS(); } +bool JReactNativeFeatureFlagsCxxInterop::iosEarlyTurboModuleDiscovery( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::iosEarlyTurboModuleDiscovery(); +} + bool JReactNativeFeatureFlagsCxxInterop::perfMonitorV2Enabled( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::perfMonitorV2Enabled(); @@ -966,6 +977,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "hideOffscreenVirtualViewsOnIOS", JReactNativeFeatureFlagsCxxInterop::hideOffscreenVirtualViewsOnIOS), + makeNativeMethod( + "iosEarlyTurboModuleDiscovery", + JReactNativeFeatureFlagsCxxInterop::iosEarlyTurboModuleDiscovery), makeNativeMethod( "perfMonitorV2Enabled", JReactNativeFeatureFlagsCxxInterop::perfMonitorV2Enabled), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index 95ead5f18e1fb7..741c6600a3d563 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -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<<90f0583b9d527a1291431a8318f10356>> + * @generated SignedSource<<8eb2ab1bec309868f89e24ad99ad14f0>> */ /** @@ -174,6 +174,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool hideOffscreenVirtualViewsOnIOS( facebook::jni::alias_ref); + static bool iosEarlyTurboModuleDiscovery( + facebook::jni::alias_ref); + static bool perfMonitorV2Enabled( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index abbbbada0d54ca..7c575ee9dd6aae 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -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<<6ff8aafa0de2f6c5cf8b42e0d43302e9>> + * @generated SignedSource<<36d94f6f70fde06dd23ca68804d99181>> */ /** @@ -218,6 +218,10 @@ bool ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS() { return getAccessor().hideOffscreenVirtualViewsOnIOS(); } +bool ReactNativeFeatureFlags::iosEarlyTurboModuleDiscovery() { + return getAccessor().iosEarlyTurboModuleDiscovery(); +} + bool ReactNativeFeatureFlags::perfMonitorV2Enabled() { return getAccessor().perfMonitorV2Enabled(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index b2fd0f4d5d915b..22e313cfd29cb6 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -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<> + * @generated SignedSource<> */ /** @@ -279,6 +279,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool hideOffscreenVirtualViewsOnIOS(); + /** + * Enables creating Module Holders for TurboModules before the JS Runtime is started, iOS only. Android already creates them early. + */ + RN_EXPORT static bool iosEarlyTurboModuleDiscovery(); + /** * Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index d8dc0377858e88..ec92ae1688762f 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -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<<1affcd93b19e37b0c2777263bac0fa07>> + * @generated SignedSource<> */ /** @@ -893,6 +893,24 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::iosEarlyTurboModuleDiscovery() { + auto flagValue = iosEarlyTurboModuleDiscovery_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(48, "iosEarlyTurboModuleDiscovery"); + + flagValue = currentProvider_->iosEarlyTurboModuleDiscovery(); + iosEarlyTurboModuleDiscovery_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() { auto flagValue = perfMonitorV2Enabled_.load(); @@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(48, "perfMonitorV2Enabled"); + markFlagAsAccessed(49, "perfMonitorV2Enabled"); flagValue = currentProvider_->perfMonitorV2Enabled(); perfMonitorV2Enabled_ = flagValue; @@ -920,7 +938,7 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(49, "preparedTextCacheSize"); + markFlagAsAccessed(50, "preparedTextCacheSize"); flagValue = currentProvider_->preparedTextCacheSize(); preparedTextCacheSize_ = flagValue; @@ -938,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(50, "preventShadowTreeCommitExhaustion"); + markFlagAsAccessed(51, "preventShadowTreeCommitExhaustion"); flagValue = currentProvider_->preventShadowTreeCommitExhaustion(); preventShadowTreeCommitExhaustion_ = flagValue; @@ -956,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::releaseImageDataWhenConsumed() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(51, "releaseImageDataWhenConsumed"); + markFlagAsAccessed(52, "releaseImageDataWhenConsumed"); flagValue = currentProvider_->releaseImageDataWhenConsumed(); releaseImageDataWhenConsumed_ = flagValue; @@ -974,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(52, "shouldPressibilityUseW3CPointerEventsForHover"); + markFlagAsAccessed(53, "shouldPressibilityUseW3CPointerEventsForHover"); flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover(); shouldPressibilityUseW3CPointerEventsForHover_ = flagValue; @@ -992,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(53, "skipActivityIdentityAssertionOnHostPause"); + markFlagAsAccessed(54, "skipActivityIdentityAssertionOnHostPause"); flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause(); skipActivityIdentityAssertionOnHostPause_ = flagValue; @@ -1010,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::sweepActiveTouchOnChildNativeGesturesAndro // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(54, "sweepActiveTouchOnChildNativeGesturesAndroid"); + markFlagAsAccessed(55, "sweepActiveTouchOnChildNativeGesturesAndroid"); flagValue = currentProvider_->sweepActiveTouchOnChildNativeGesturesAndroid(); sweepActiveTouchOnChildNativeGesturesAndroid_ = flagValue; @@ -1028,7 +1046,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(55, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(56, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -1046,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(56, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(57, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -1064,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(57, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(58, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -1082,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(58, "useFabricInterop"); + markFlagAsAccessed(59, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -1100,7 +1118,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroi // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(59, "useNativeEqualsInNativeReadableArrayAndroid"); + markFlagAsAccessed(60, "useNativeEqualsInNativeReadableArrayAndroid"); flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid(); useNativeEqualsInNativeReadableArrayAndroid_ = flagValue; @@ -1118,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(60, "useNativeTransformHelperAndroid"); + markFlagAsAccessed(61, "useNativeTransformHelperAndroid"); flagValue = currentProvider_->useNativeTransformHelperAndroid(); useNativeTransformHelperAndroid_ = flagValue; @@ -1136,7 +1154,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(61, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(62, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -1154,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(62, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(63, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -1172,7 +1190,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(63, "useRawPropsJsiValue"); + markFlagAsAccessed(64, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -1190,7 +1208,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(64, "useShadowNodeStateOnClone"); + markFlagAsAccessed(65, "useShadowNodeStateOnClone"); flagValue = currentProvider_->useShadowNodeStateOnClone(); useShadowNodeStateOnClone_ = flagValue; @@ -1208,7 +1226,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(65, "useTurboModuleInterop"); + markFlagAsAccessed(66, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1226,7 +1244,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(66, "useTurboModules"); + markFlagAsAccessed(67, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; @@ -1244,7 +1262,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(67, "virtualViewPrerenderRatio"); + markFlagAsAccessed(68, "virtualViewPrerenderRatio"); flagValue = currentProvider_->virtualViewPrerenderRatio(); virtualViewPrerenderRatio_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index ee48c0e3204010..645a2ace98b948 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -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<> + * @generated SignedSource<<2ac8a91497c7e0ac8d65c97be1e1391e>> */ /** @@ -80,6 +80,7 @@ class ReactNativeFeatureFlagsAccessor { bool fuseboxEnabledRelease(); bool fuseboxNetworkInspectionEnabled(); bool hideOffscreenVirtualViewsOnIOS(); + bool iosEarlyTurboModuleDiscovery(); bool perfMonitorV2Enabled(); double preparedTextCacheSize(); bool preventShadowTreeCommitExhaustion(); @@ -111,7 +112,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 68> accessedFeatureFlags_; + std::array, 69> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> cdpInteractionMetricsEnabled_; @@ -161,6 +162,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> fuseboxEnabledRelease_; std::atomic> fuseboxNetworkInspectionEnabled_; std::atomic> hideOffscreenVirtualViewsOnIOS_; + std::atomic> iosEarlyTurboModuleDiscovery_; std::atomic> perfMonitorV2Enabled_; std::atomic> preparedTextCacheSize_; std::atomic> preventShadowTreeCommitExhaustion_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 5dae3f5f9e8e91..9b09402af96b57 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -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<> + * @generated SignedSource<<015409a105e508e1a8abd58156a0c6b9>> */ /** @@ -219,6 +219,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool iosEarlyTurboModuleDiscovery() override { + return false; + } + bool perfMonitorV2Enabled() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 135e3278fbef06..c84f20f352bfd4 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -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<<757089d037ab0f7c6cda11b079dafa2c>> + * @generated SignedSource<<1fbecec0f27a2c8f601fd687c237ba30>> */ /** @@ -477,6 +477,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::hideOffscreenVirtualViewsOnIOS(); } + bool iosEarlyTurboModuleDiscovery() override { + auto value = values_["iosEarlyTurboModuleDiscovery"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::iosEarlyTurboModuleDiscovery(); + } + bool perfMonitorV2Enabled() override { auto value = values_["perfMonitorV2Enabled"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 9aa389ae11fdc1..c19c2df96e72ba 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -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<<33c7ddecd2532875e5144039927daa07>> + * @generated SignedSource<<7e49aa4eca6c0fcd766129d97b90ee64>> */ /** @@ -73,6 +73,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool fuseboxEnabledRelease() = 0; virtual bool fuseboxNetworkInspectionEnabled() = 0; virtual bool hideOffscreenVirtualViewsOnIOS() = 0; + virtual bool iosEarlyTurboModuleDiscovery() = 0; virtual bool perfMonitorV2Enabled() = 0; virtual double preparedTextCacheSize() = 0; virtual bool preventShadowTreeCommitExhaustion() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h index 33f3a8f84ec513..bee88e4abbeb42 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h @@ -22,6 +22,14 @@ @protocol RCTTurboModuleManagerDelegate +@optional + +/** + * Returns the names of the available TurboModules registered ahead of JS runtime in the delegate. Implement it if you + * want to be able to create certain module holders early. + */ +- (nonnull NSArray *)getModuleNames; + /** * Given a module name, return its actual class. If nil is returned, basic ObjC class lookup is performed. */ @@ -49,7 +57,7 @@ (std::shared_ptr)jsInvoker; /** - * Return a pre-initialized list of leagcy native modules. + * Return a pre-initialized list of legacy native modules. * These modules shouldn't be TurboModule-compatible (i.e: they should not conform to RCTTurboModule). * * This method is only used by the TurboModule interop layer. diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm index 5168bbf415d1a7..f9df2376a4c98b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm @@ -264,6 +264,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge selector:@selector(bridgeDidInvalidateModules:) name:RCTBridgeDidInvalidateModulesNotification object:nil]; + + if(ReactNativeFeatureFlags::iosEarlyTurboModuleDiscovery()) { + [self _discoverModules]; + } } return self; } @@ -473,6 +477,16 @@ - (instancetype)initWithBridgeProxy:(RCTBridgeProxy *)bridgeProxy #pragma mark - Private Methods +- (void)_discoverModules{ + if(![_delegate respondsToSelector:@selector(getModuleNames)]) { + return; + } + NSArray *moduleNames = [_delegate getModuleNames]; + for (NSString *moduleName in moduleNames) { + [self _getOrCreateModuleHolder:[moduleName UTF8String]]; + } +} + - (BOOL)_isTurboModule:(const char *)moduleName { Class moduleClass = [self _getModuleClassFromName:moduleName]; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index bf7582dfdc74c7..8ff6a1f35c4904 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -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<<07c2f85e56246236c44e30e936cb9a40>> + * @generated SignedSource<<18bb6a659df8134d3028640cee2f1fe6>> */ /** @@ -284,6 +284,11 @@ bool NativeReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS( return ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS(); } +bool NativeReactNativeFeatureFlags::iosEarlyTurboModuleDiscovery( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::iosEarlyTurboModuleDiscovery(); +} + bool NativeReactNativeFeatureFlags::perfMonitorV2Enabled( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::perfMonitorV2Enabled(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 179c27cee848b5..ca6b83d6574caa 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -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<<57b7676134d7d0782f576b852c71aa1f>> + * @generated SignedSource<<56ac4e64ed4afa5aa0b411e6e5198a11>> */ /** @@ -132,6 +132,8 @@ class NativeReactNativeFeatureFlags bool hideOffscreenVirtualViewsOnIOS(jsi::Runtime& runtime); + bool iosEarlyTurboModuleDiscovery(jsi::Runtime& runtime); + bool perfMonitorV2Enabled(jsi::Runtime& runtime); double preparedTextCacheSize(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index 62585c6129dd49..aebeb5c0d92103 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -226,6 +226,13 @@ - (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path #pragma mark - RCTTurboModuleManagerDelegate +- (NSArray *)getModuleNames{ + if ([_appTMMDelegate respondsToSelector:@selector(getModuleNames)]) { + return [_appTMMDelegate getModuleNames]; + } + return @[]; +} + - (Class)getModuleClassFromName:(const char *)name { return [_appTMMDelegate getModuleClassFromName:name]; diff --git a/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap b/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap index 1f04a84d2400e0..9290921226c02c 100644 --- a/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap +++ b/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap @@ -69,6 +69,10 @@ exports[`execute test-app "RCTAppDependencyProvider.mm" should match snapshot 1` return RCTModuleProviders.moduleProviders; } +- (nonnull NSArray *)moduleNames { + return RCTModuleProviders.moduleNames; +} + @end " `; @@ -88,6 +92,7 @@ exports[`execute test-app "RCTModuleProviders.h" should match snapshot 1`] = ` @interface RCTModuleProviders: NSObject + (NSDictionary> *)moduleProviders; ++ (NSArray *)moduleNames; @end " @@ -155,6 +160,23 @@ exports[`execute test-app "RCTModuleProviders.mm" should match snapshot 1`] = ` return providers; } ++ (nonnull NSArray *)moduleNames +{ + NSArray * moduleNames = @[@\\"RCTTestAppDeprecatedImageURLLoader\\", +@\\"RCTTestAppDeprecatedURLRequestHandler\\", +@\\"RCTTestAppDeprecatedImageDataDecoder\\", +@\\"RCTTestAppImageURLLoader\\", +@\\"RCTTestAppURLRequestHandler\\", +@\\"RCTTestAppImageDataDecoder\\", +@\\"RCTTestLibraryDeprecatedImageURLLoader\\", +@\\"RCTTestLibraryDeprecatedURLRequestHandler\\", +@\\"RCTTestLibraryDeprecatedImageDataDecoder\\", +@\\"RCTTestLibraryImageURLLoader\\", +@\\"RCTTestLibraryURLRequestHandler\\", +@\\"RCTTestLibraryImageDataDecoder\\"]; + return moduleNames; +} + @end " `; @@ -576,6 +598,10 @@ exports[`execute test-app-legacy "RCTAppDependencyProvider.mm" should match snap return RCTModuleProviders.moduleProviders; } +- (nonnull NSArray *)moduleNames { + return RCTModuleProviders.moduleNames; +} + @end " `; @@ -595,6 +621,7 @@ exports[`execute test-app-legacy "RCTModuleProviders.h" should match snapshot 1` @interface RCTModuleProviders: NSObject + (NSDictionary> *)moduleProviders; ++ (NSArray *)moduleNames; @end " @@ -653,6 +680,14 @@ exports[`execute test-app-legacy "RCTModuleProviders.mm" should match snapshot 1 return providers; } ++ (nonnull NSArray *)moduleNames +{ + NSArray * moduleNames = @[@\\"RCTTestAppDeprecatedImageURLLoader\\", +@\\"RCTTestAppDeprecatedURLRequestHandler\\", +@\\"RCTTestAppDeprecatedImageDataDecoder\\"]; + return moduleNames; +} + @end " `; diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js b/packages/react-native/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js index 1c8051db5ba586..677660d9d93729 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js @@ -36,7 +36,7 @@ function generateRCTModuleProviders( ) { fs.mkdirSync(outputDir, {recursive: true}); // Generate Header File - codegenLog('Generating RCTModulesProvider.h'); + codegenLog('Generating RCTModuleProviders.h'); const templateH = fs.readFileSync(MODULE_PROVIDERS_H_TEMPLATE_PATH, 'utf8'); const finalPathH = path.join(outputDir, 'RCTModuleProviders.h'); fs.writeFileSync(finalPathH, templateH); @@ -98,6 +98,13 @@ function generateRCTModuleProviders( } } + const moduleNames = Object.keys(modulesInLibraries) + .flatMap(library => { + const modules = modulesInLibraries[library]; + return modules.map(({className}) => `@"${className}"`); + }) + .join(',\n'); + const modulesMapping = Object.keys(modulesInLibraries) .flatMap(library => { const modules = modulesInLibraries[library]; @@ -108,9 +115,11 @@ function generateRCTModuleProviders( .join('\n'); // Generate implementation file - const templateMM = fs - .readFileSync(MODULE_PROVIDERS_MM_TEMPLATE_PATH, 'utf8') - .replace(/{moduleMapping}/, modulesMapping); + let templateMM = fs.readFileSync(MODULE_PROVIDERS_MM_TEMPLATE_PATH, 'utf8'); + + templateMM = templateMM.replace(/{moduleNames}/, moduleNames); + templateMM = templateMM.replace(/{moduleMapping}/, modulesMapping); + const finalPathMM = path.join(outputDir, 'RCTModuleProviders.mm'); fs.writeFileSync(finalPathMM, templateMM); codegenLog(`Generated artifact: ${finalPathMM}`); diff --git a/packages/react-native/scripts/codegen/templates/RCTAppDependencyProviderMM.template b/packages/react-native/scripts/codegen/templates/RCTAppDependencyProviderMM.template index b76c468c8a8714..4ed28b3dcebb06 100644 --- a/packages/react-native/scripts/codegen/templates/RCTAppDependencyProviderMM.template +++ b/packages/react-native/scripts/codegen/templates/RCTAppDependencyProviderMM.template @@ -37,4 +37,8 @@ return RCTModuleProviders.moduleProviders; } +- (nonnull NSArray *)moduleNames { + return RCTModuleProviders.moduleNames; +} + @end diff --git a/packages/react-native/scripts/codegen/templates/RCTModuleProvidersH.template b/packages/react-native/scripts/codegen/templates/RCTModuleProvidersH.template index aff637c69206f0..f8f99c397873f9 100644 --- a/packages/react-native/scripts/codegen/templates/RCTModuleProvidersH.template +++ b/packages/react-native/scripts/codegen/templates/RCTModuleProvidersH.template @@ -12,5 +12,6 @@ @interface RCTModuleProviders: NSObject + (NSDictionary> *)moduleProviders; ++ (NSArray *)moduleNames; @end diff --git a/packages/react-native/scripts/codegen/templates/RCTModuleProvidersMM.template b/packages/react-native/scripts/codegen/templates/RCTModuleProvidersMM.template index b1fb2c725050d1..ac5b2456c34595 100644 --- a/packages/react-native/scripts/codegen/templates/RCTModuleProvidersMM.template +++ b/packages/react-native/scripts/codegen/templates/RCTModuleProvidersMM.template @@ -48,4 +48,10 @@ return providers; } ++ (nonnull NSArray *)moduleNames +{ + NSArray * moduleNames = @[{moduleNames}]; + return moduleNames; +} + @end diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 545563067bfe70..632a61e722d964 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -559,6 +559,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + iosEarlyTurboModuleDiscovery: { + defaultValue: false, + metadata: { + dateAdded: '2025-08-15', + description: + 'Enables creating Module Holders for TurboModules before the JS Runtime is started, iOS only. Android already creates them early.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, perfMonitorV2Enabled: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 215e874d68e3ec..36ff4e21ba8954 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<<29d1ff8e6948e8c8cf286769d8c1ff81>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -95,6 +95,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ fuseboxEnabledRelease: Getter, fuseboxNetworkInspectionEnabled: Getter, hideOffscreenVirtualViewsOnIOS: Getter, + iosEarlyTurboModuleDiscovery: Getter, perfMonitorV2Enabled: Getter, preparedTextCacheSize: Getter, preventShadowTreeCommitExhaustion: Getter, @@ -373,6 +374,10 @@ export const fuseboxNetworkInspectionEnabled: Getter = createNativeFlag * Hides offscreen VirtualViews on iOS by setting hidden = YES to avoid extra cost of views */ export const hideOffscreenVirtualViewsOnIOS: Getter = createNativeFlagGetter('hideOffscreenVirtualViewsOnIOS', false); +/** + * Enables creating Module Holders for TurboModules before the JS Runtime is started, iOS only. Android already creates them early. + */ +export const iosEarlyTurboModuleDiscovery: Getter = createNativeFlagGetter('iosEarlyTurboModuleDiscovery', false); /** * Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index c1a41088665e4e..ff968b00e61cc2 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.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<<4bd1c1bd236e9afa5b010f58683d5e67>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -73,6 +73,7 @@ export interface Spec extends TurboModule { +fuseboxEnabledRelease?: () => boolean; +fuseboxNetworkInspectionEnabled?: () => boolean; +hideOffscreenVirtualViewsOnIOS?: () => boolean; + +iosEarlyTurboModuleDiscovery?: () => boolean; +perfMonitorV2Enabled?: () => boolean; +preparedTextCacheSize?: () => number; +preventShadowTreeCommitExhaustion?: () => boolean; diff --git a/packages/rn-tester/package.json b/packages/rn-tester/package.json index 9961db5e82b5a9..6606ce85e82cad 100644 --- a/packages/rn-tester/package.json +++ b/packages/rn-tester/package.json @@ -53,6 +53,9 @@ "RNTMyNativeView": { "className": "RNTMyNativeViewComponentView" } + }, + "modulesProvider": { + "SampleTurboModule": "RCTSampleTurboModule" } } },