Skip to content

Commit

Permalink
Make NativeModules.foo also load turbo modules (#47598)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #47598

## 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

fbshipit-source-id: 10883c292b78759fceac5bd984e0cdf8a679fc67
  • Loading branch information
RSNara authored and facebook-github-bot committed Nov 19, 2024
1 parent d1b0e9a commit cc5f17d
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: TurboModule>(name: string): ?T {
if (turboModuleProxy != null) {
const module: ?T = turboModuleProxy(name);
Expand All @@ -27,8 +24,11 @@ function requireModule<T: TurboModule>(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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,25 @@ using namespace facebook;
namespace facebook::react {

class BridgelessNativeModuleProxy : public jsi::HostObject {
std::unique_ptr<TurboModuleBinding> binding_;
TurboModuleBinding turboBinding_;
std::unique_ptr<TurboModuleBinding> legacyBinding_;

public:
BridgelessNativeModuleProxy(std::unique_ptr<TurboModuleBinding> binding)
: binding_(std::move(binding)) {}
BridgelessNativeModuleProxy(
jsi::Runtime& runtime,
TurboModuleProviderFunctionType&& moduleProvider,
TurboModuleProviderFunctionType&& legacyModuleProvider,
std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection)
: turboBinding_(
runtime,
std::move(moduleProvider),
longLivedObjectCollection),
legacyBinding_(
legacyModuleProvider ? std::make_unique<TurboModuleBinding>(
runtime,
std::move(legacyModuleProvider),
longLivedObjectCollection)
: nullptr) {}

jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& name) override {
/**
Expand All @@ -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(
Expand Down Expand Up @@ -79,44 +98,46 @@ void TurboModuleBinding::install(
TurboModuleProviderFunctionType&& moduleProvider,
TurboModuleProviderFunctionType&& legacyModuleProvider,
std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection) {
runtime.global().setProperty(
// TODO(T208105802): We can get this information from the native side!
auto isBridgeless = runtime.global().hasProperty(runtime, "RN$Bridgeless");

if (!isBridgeless) {
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<TurboModuleBinding>(
std::make_shared<BridgelessNativeModuleProxy>(
runtime,
std::move(moduleProvider),
std::move(legacyModuleProvider),
longLivedObjectCollection)
: nullptr;
auto nativeModuleProxy = std::make_shared<BridgelessNativeModuleProxy>(
std::move(turboModuleBinding));
defineReadOnlyGlobal(
runtime, "RN$TurboInterop", jsi::Value(rnTurboInterop));
defineReadOnlyGlobal(
runtime,
"nativeModuleProxy",
jsi::Object::createFromHostObject(runtime, nativeModuleProxy));
}
longLivedObjectCollection)));
}

TurboModuleBinding::~TurboModuleBinding() {
Expand Down

0 comments on commit cc5f17d

Please sign in to comment.