Skip to content

Commit 78ea1f6

Browse files
Compile out RCTGetModuleClasses/RCTRegisterModule when both legacy interops are removed (#57670)
Summary: Changelog: [iOS][Changed] - Compile out `RCTGetModuleClasses`/`RCTRegisterModule` and skip static module registration when both `RCT_REMOVE_LEGACY_MODULE_INTEROP` and `RCT_REMOVE_LEGACY_COMPONENT_INTEROP` are defined `RCTGetModuleClasses()` and the `RCTModuleClasses` registry it reads (populated by `RCTRegisterModule`) exist solely to support the two legacy interop layers. Every reader of the registry is already gated behind either `RCT_REMOVE_LEGACY_MODULE_INTEROP` (TurboModule ⇄ legacy NativeModule interop) or `RCT_REMOVE_LEGACY_COMPONENT_INTEROP` (Fabric ⇄ legacy ViewManager interop). When an app defines **both** macros, the registry has no readers and the function, its backing statics, and `RCTRegisterModule` are dead code. This diff compiles them out in that configuration: - `React/Base/RCTBridge.mm`: guard `RCTModuleClasses`/`RCTModuleClassesSyncQueue`, `RCTGetModuleClasses()`, `getCoreModuleClasses()`, and `RCTRegisterModule()` behind `#if !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)`. The old-arch warning helpers (`getModulesLoadedWithOldArch` et al.) stay compiled in — they have an external caller in `RCTInstance.mm` — and simply observe an empty list once the registry's only writer is gone. - `React/Base/RCTBridge+Private.h`: guard the matching `RCT_EXTERN` declarations. - `React/Base/RCTBridgeModule.h`: add a "both-removed" variant of `RCT_EXPORT_MODULE` / `RCT_EXPORT_MODULE_NO_LOAD` that emits only `+moduleName` and omits the `RCTRegisterModule` call, so native modules still link when the symbol is gone. - `RCTLegacyUIManagerConstantsProvider.{h,mm}`: wrap the file body in `#ifndef RCT_REMOVE_LEGACY_COMPONENT_INTEROP`, matching the sibling `LegacyViewManagerInterop*` files. It was the one caller of `RCTGetModuleClasses` whose file body was not already guarded. - `fbobjc/Libraries/FBReactModuleRegistration/FBReactModuleRegistration.mm`: the FIT/new-arch path (`RCT_REMOVE_LEGACY_ARCH`) hand-calls `RCTRegisterModule`. On `cove-ios`, which sets all three macros, that symbol is now compiled out, so the call is additionally gated to only run when `RCTRegisterModule` still exists. The registry has no readers in that config, so this is a no-op. The default build (neither/one macro set) is behavior-unchanged: all guarded code is still compiled in. Differential Revision: D113555374
1 parent 834721f commit 78ea1f6

5 files changed

Lines changed: 28 additions & 0 deletions

File tree

packages/react-native/React/Base/RCTBridge+Private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
@class RCTModuleData;
1212
@protocol RCTJavaScriptExecutor;
1313

14+
#if !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
1415
RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
1516
RCT_EXTERN void RCTRegisterModule(Class);
17+
#endif // !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
1618

1719
@interface RCTBridge ()
1820

packages/react-native/React/Base/RCTBridge.mm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#import "RCTReloadCommand.h"
3232
#import "RCTUtils.h"
3333

34+
#if !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
3435
static NSMutableArray<Class> *RCTModuleClasses;
3536
static dispatch_queue_t RCTModuleClassesSyncQueue;
3637
NSArray<Class> *RCTGetModuleClasses(void)
@@ -115,6 +116,7 @@
115116

116117
return coreModuleClasses;
117118
}
119+
#endif // !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
118120

119121
static NSMutableArray<NSString *> *modulesLoadedWithOldArch;
120122
void addModuleLoadedWithOldArch(NSString * /*moduleName*/);
@@ -133,6 +135,7 @@ void addModuleLoadedWithOldArch(NSString *moduleName)
133135
return modulesLoadedWithOldArch;
134136
}
135137

138+
#if !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
136139
/**
137140
* Register the given class as a bridge module. All modules must be registered
138141
* prior to the first bridge initialization.
@@ -161,6 +164,7 @@ void RCTRegisterModule(Class moduleClass)
161164
[RCTModuleClasses addObject:moduleClass];
162165
});
163166
}
167+
#endif // !defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) || !defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
164168

165169
/**
166170
* This function returns the module name for a given class.

packages/react-native/React/Base/RCTBridgeModule.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ RCT_EXTERN_C_END
6969
* will be used as the JS module name. If omitted, the JS module name will
7070
* match the Objective-C class name.
7171
*/
72+
#if defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) && defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
73+
74+
// With both legacy interop layers removed, RCTRegisterModule is compiled out, so
75+
// static module registration is a no-op: only the JS module name is emitted.
76+
#define RCT_EXPORT_MODULE(js_name) \
77+
+(NSString *)moduleName \
78+
{ \
79+
return @ #js_name; \
80+
}
81+
82+
#else
83+
7284
#ifndef RCT_DISABLE_STATIC_MODULE_REGISTRATION
7385
#define RCT_EXPORT_MODULE(js_name) \
7486
RCT_EXTERN void RCTRegisterModule(Class); \
@@ -108,6 +120,8 @@ RCT_EXTERN_C_END
108120
RCTRegisterModule([objc_name class]); \
109121
}
110122

123+
#endif // defined(RCT_REMOVE_LEGACY_MODULE_INTEROP) && defined(RCT_REMOVE_LEGACY_COMPONENT_INTEROP)
124+
111125
// Implemented by RCT_EXPORT_MODULE
112126
+ (NSString *)moduleName;
113127

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTLegacyUIManagerConstantsProvider.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#pragma once
99

10+
#ifndef RCT_REMOVE_LEGACY_COMPONENT_INTEROP
11+
1012
#include <jsi/jsi.h>
1113

1214
namespace facebook::react {
@@ -17,3 +19,5 @@ namespace facebook::react {
1719
*/
1820
void installLegacyUIManagerConstantsProviderBinding(jsi::Runtime &runtime);
1921
} // namespace facebook::react
22+
23+
#endif // RCT_REMOVE_LEGACY_COMPONENT_INTEROP

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTLegacyUIManagerConstantsProvider.mm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include "RCTLegacyUIManagerConstantsProvider.h"
99

10+
#ifndef RCT_REMOVE_LEGACY_COMPONENT_INTEROP
11+
1012
#import <React/RCTBridge+Private.h>
1113
#import <React/RCTComponentData.h>
1214
#import <React/RCTUIManager.h>
@@ -41,3 +43,5 @@ void installLegacyUIManagerConstantsProviderBinding(jsi::Runtime &runtime)
4143
LegacyUIManagerConstantsProviderBinding::install(runtime, "getConstants", getConstants);
4244
}
4345
} // namespace facebook::react
46+
47+
#endif // RCT_REMOVE_LEGACY_COMPONENT_INTEROP

0 commit comments

Comments
 (0)