From 860439c6a1ecf5d6fd95045c7de63c65e869cda5 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 15 Nov 2024 14:08:02 -0800 Subject: [PATCH] Make NativeModules.foo also load turbo modules Summary: ## Changes Now: - in bridgeless, NativeModules.foo will also return turbo modules. And, global.__turboModuleProxy no longer exists. - in bridge, nothing changes. | **JS API** | **Bridge** | ***[Before]* Bridgeless** | ***[Before]* Bridgeless w/ Interop**| ***[After]* Bridgeless** | global.__turboModuleProxy | turbo modules | turbo modules | turbo modules |**deleted** | global.nativeModuleProxy | legacy modules | error | legacy modules | turbo + legacy modules ## Justification This reduces the cost for adopting the new architecture: - Prior, you had to migrate the module itself, **and** all its callsites: NativeModules.foo -> NativeFoo - Now, you have to migrate the module itself **only**. This simplifies the interop layer logic in bridgeless: all modules come from the same thing. Changelog: [General][Breaking] Bridgeless: Make NativeModules.foo load turbomodules (unset turboModuleProxy in bridgeless). Reviewed By: javache Differential Revision: D65896934 --- .../TurboModule/TurboModuleRegistry.js | 10 +- .../core/ReactCommon/TurboModuleBinding.cpp | 106 +++++++++++------- 2 files changed, 68 insertions(+), 48 deletions(-) diff --git a/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js b/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js index 9f2a3735861642..135be5bca89d7a 100644 --- a/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js +++ b/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js @@ -16,9 +16,6 @@ const NativeModules = require('../BatchedBridge/NativeModules'); const turboModuleProxy = global.__turboModuleProxy; -const useLegacyNativeModuleInterop = - global.RN$Bridgeless !== true || global.RN$TurboInterop === true; - function requireModule(name: string): ?T { if (turboModuleProxy != null) { const module: ?T = turboModuleProxy(name); @@ -27,8 +24,11 @@ function requireModule(name: string): ?T { } } - if (useLegacyNativeModuleInterop) { - // Backward compatibility layer during migration. + if ( + global.RN$Bridgeless !== true || + global.RN$TurboInterop === true || + global.RN$UnifiedNativeModuleProxy === true + ) { const legacyModule: ?T = NativeModules[name]; if (legacyModule != null) { return legacyModule; diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp index 1bc4d716e9a9d0..0836cb6eda815b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp @@ -17,11 +17,25 @@ using namespace facebook; namespace facebook::react { class BridgelessNativeModuleProxy : public jsi::HostObject { - std::unique_ptr binding_; + TurboModuleBinding turboBinding_; + std::unique_ptr legacyBinding_; public: - BridgelessNativeModuleProxy(std::unique_ptr binding) - : binding_(std::move(binding)) {} + BridgelessNativeModuleProxy( + jsi::Runtime& runtime, + TurboModuleProviderFunctionType&& moduleProvider, + TurboModuleProviderFunctionType&& legacyModuleProvider, + std::shared_ptr longLivedObjectCollection) + : turboBinding_( + runtime, + std::move(moduleProvider), + longLivedObjectCollection), + legacyBinding_( + legacyModuleProvider ? std::make_unique( + runtime, + std::move(legacyModuleProvider), + longLivedObjectCollection) + : nullptr) {} jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& name) override { /** @@ -42,14 +56,19 @@ class BridgelessNativeModuleProxy : public jsi::HostObject { return jsi::Value(false); } - if (binding_) { - return binding_->getModule(runtime, moduleName); + auto turboModule = turboBinding_.getModule(runtime, moduleName); + if (turboModule.isObject()) { + return turboModule; } - throw jsi::JSError( - runtime, - "Tried to access NativeModule \"" + name.utf8(runtime) + - "\" from the bridge. This isn't allowed in Bridgeless mode."); + if (legacyBinding_) { + auto legacyModule = legacyBinding_->getModule(runtime, moduleName); + if (legacyModule.isObject()) { + return legacyModule; + } + } + + return jsi::Value::null(); } void set( @@ -79,44 +98,45 @@ void TurboModuleBinding::install( TurboModuleProviderFunctionType&& moduleProvider, TurboModuleProviderFunctionType&& legacyModuleProvider, std::shared_ptr longLivedObjectCollection) { - runtime.global().setProperty( + auto nativeModuleProxy = + runtime.global().getProperty(runtime, "nativeModuleProxy"); + if (nativeModuleProxy.isObject()) { + runtime.global().setProperty( + runtime, + "__turboModuleProxy", + jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"), + 1, + [binding = TurboModuleBinding( + runtime, + std::move(moduleProvider), + longLivedObjectCollection)]( + jsi::Runtime& rt, + const jsi::Value& /*thisVal*/, + const jsi::Value* args, + size_t count) { + if (count < 1) { + throw std::invalid_argument( + "__turboModuleProxy must be called with at least 1 argument"); + } + std::string moduleName = args[0].getString(rt).utf8(rt); + return binding.getModule(rt, moduleName); + })); + return; + } + + defineReadOnlyGlobal(runtime, "RN$UnifiedNativeModuleProxy", true); + defineReadOnlyGlobal( runtime, - "__turboModuleProxy", - jsi::Function::createFromHostFunction( + "nativeModuleProxy", + jsi::Object::createFromHostObject( runtime, - jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"), - 1, - [binding = TurboModuleBinding( - runtime, std::move(moduleProvider), longLivedObjectCollection)]( - jsi::Runtime& rt, - const jsi::Value& thisVal, - const jsi::Value* args, - size_t count) { - if (count < 1) { - throw std::invalid_argument( - "__turboModuleProxy must be called with at least 1 argument"); - } - std::string moduleName = args[0].getString(rt).utf8(rt); - return binding.getModule(rt, moduleName); - })); - - if (runtime.global().hasProperty(runtime, "RN$Bridgeless")) { - bool rnTurboInterop = legacyModuleProvider != nullptr; - auto turboModuleBinding = legacyModuleProvider - ? std::make_unique( + std::make_shared( runtime, + std::move(moduleProvider), std::move(legacyModuleProvider), - longLivedObjectCollection) - : nullptr; - auto nativeModuleProxy = std::make_shared( - std::move(turboModuleBinding)); - defineReadOnlyGlobal( - runtime, "RN$TurboInterop", jsi::Value(rnTurboInterop)); - defineReadOnlyGlobal( - runtime, - "nativeModuleProxy", - jsi::Object::createFromHostObject(runtime, nativeModuleProxy)); - } + longLivedObjectCollection))); } TurboModuleBinding::~TurboModuleBinding() {