feat: Add CallInvoker to installJSIBindings(..)/BindingsInstaller#46851
feat: Add CallInvoker to installJSIBindings(..)/BindingsInstaller#46851mrousavy wants to merge 13 commits into
CallInvoker to installJSIBindings(..)/BindingsInstaller#46851Conversation
|
Note: This is technically not backwards compatible since it adds a new parameter to an existing function. If anyone uses this, they need to update their method signature. I am not aware of any public repos using |
|
Will import locally to test, but would be great to think about ways to make this backwards compatible. |
|
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
|
Build failed because I am not passing along the Is there any way to access the |
Sure - I'll add both methods. |
|
EDIT: I did just that. Let me know if there is already an existing instance of |
| timerManager_->attachGlobals(runtime); | ||
|
|
||
| bindingsInstallFunc(runtime); | ||
| auto callInvoker = std::make_shared<RuntimeSchedulerCallInvoker>(runtimeScheduler_); |
There was a problem hiding this comment.
We should able to get to the existing one and avoid allocating a new one.
There was a problem hiding this comment.
How? Do you have any pointers for me?
There was a problem hiding this comment.
I'll have a look. I assumed this would be accessible from Reactinstance, since C++ TurboModules get it, but I may be wrong.
…ule/ReactCommon/BindingsInstallerHolder.cpp Co-authored-by: Pieter De Baets <pieter.debaets@gmail.com>
…form/ios/ReactCommon/RCTTurboModuleWithJSIBindings.h Co-authored-by: Pieter De Baets <pieter.debaets@gmail.com>
| #include <jsireact/JSIExecutor.h> | ||
| #include <react/featureflags/ReactNativeFeatureFlags.h> | ||
| #include <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h> | ||
| #include <react/renderer/RuntimeSchedulerCallInvoker.h> |
There was a problem hiding this comment.
| #include <react/renderer/RuntimeSchedulerCallInvoker.h> | |
| #include <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h> |
|
Actually, we should only support this for the TurboModule-based bindings installer - and TurboModuleManager already has the jsCallInvoker. I don't think you need any of the changes to ReactInstance. |
|
Sorry, you're right I messed up my local files. I built this inside another react-native app and had a few patches that conflicted with eachother. I now checked out this branch in |
| static auto constexpr kJavaDescriptor = | ||
| "Lcom/facebook/react/turbomodule/core/interfaces/BindingsInstallerHolder;"; | ||
| using BindingsInstallFunc = std::function<void(jsi::Runtime& runtime, | ||
| std::shared_ptr<CallInvoker> callInvoker)>; |
There was a problem hiding this comment.
@javache should we make this const& as well?
| _turboModuleCache.insert({moduleName, turboModule}); | ||
|
|
||
| if ([module respondsToSelector:@selector(installJSIBindingsWithRuntime:)]) { | ||
| if ([module respondsToSelector:@selector(installJSIBindingsWithRuntime:callInvoker:)]) { |
There was a problem hiding this comment.
so we do have an API to init the TM with the call invoker, i'm wondering if we can use this and then reference it in the implementation of installJSIBindingsWithRuntime:
There was a problem hiding this comment.
I mean we don't have the jsi::Runtime in there where you linked - or are you saying a TurboModule can just fetch the CallInvoker themselves using the callInvoker property (if implemented)? I guess that's fine too, but I think this API is a bit more verbose
There was a problem hiding this comment.
I think both of these options work, and perhaps for symmetry with Android, sharing the callInvoker here is nice too? But it would allow us to avoid a breaking API change here too, which is nice.
There was a problem hiding this comment.
so we do have an API to init the TM with the call invoker, i'm wondering if we can use this and then reference it in the implementation of installJSIBindingsWithRuntime:
What's the difference between this codepath and the one in https://github.com/facebook/react-native/blob/main/packages/react-native/React/Base/RCTModuleData.mm#L206-L208 ? Legacy native modules vs TurboModules? Or old bridge vs bridgeless?
There was a problem hiding this comment.
The one in RCTModuleData can not access jsi::Runtime - it both doesn't have a reference to it, and it isn't guaranteed to run on the proper Thread (legacy modules)
There was a problem hiding this comment.
so we do have an API to init the TM with the call invoker, i'm wondering if we can use this and then reference it in the implementation of installJSIBindingsWithRuntime:
https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm#L693-L697What's the difference between this codepath and the one in https://github.com/facebook/react-native/blob/main/packages/react-native/React/Base/RCTModuleData.mm#L206-L208 ? Legacy native modules vs TurboModules? Or old bridge vs bridgeless?
it's just a forward compatible API. so the idea is that you can change your code and not worry about legacy vs new arch, you will be guaranteed that your module has access to the callinvoker.
essentially in your module, you could have sth like:
- (void)installJSIBindingsWithRuntime:(jsi::Runtime &)runtime
{
auto callinvoker = self.callInvoker;
// do something with runtime & callInvoker
}
i do think having API symmetry would be nice though. i wonder if adding the CallInvoker to this argument will make the other ways of retrieving the callInvoker irrelevant.
| auto installer = getBindingsInstaller(moduleInstance); | ||
| if (installer) { | ||
| installer->cthis()->installBindings(runtime); | ||
| installer->cthis()->installBindings(runtime, jsCallInvoker_); |
There was a problem hiding this comment.
we can actually get the callInvoker off the ReactContext, but i can see how that's inapplicable here... but i'm reading all of this and i'm starting to feel like a C++ TM is more appropriate here? what's the current limitation?
There was a problem hiding this comment.
I can't use a C++ TM because
- I need backwards compatibility for now (I guess this is only a temporary thing)
- I need the
ReactApplicationContext. As far as I know, there's no way to get that in a C++ TM (since those are platform-independent)
There was a problem hiding this comment.
I need it in NitroModules.kt (init) - this will (optionally) be passed along to other Nitro Modules. But it goes through C++ first.
There was a problem hiding this comment.
I need it in
NitroModules.kt (init)- this will (optionally) be passed along to other Nitro Modules. But it goes through C++ first.
thanks! is the idea that we want to replace install with installJSIBindings?
if so, is it possible to keep the current native pipeline to pass down the CallInvoker (i.e. do what you have now), but use installJSIBindings for the runtime installation? or will there be some sort of timing issue?
i can see how ergonomically that might feel weird, what's your feeling on that?
There was a problem hiding this comment.
Yep - I want to have a clear, public and guaranteed to be future-proof API to install Nitro into the jsi::Runtime.
The current approach works, but having to annotate with @OptIn(FrameworkAPI::class) doesn't sound very public-API-like to me?
There was a problem hiding this comment.
if so, is it possible to keep the current native pipeline to pass down the CallInvoker (i.e. do what you have now), but use installJSIBindings for the runtime installation? or will there be some sort of timing issue?
Well installJSIBindings (or BindingsInstaller on Android) is accessed before I can call install() on the module. So I don't have a CallInvoker yet at that point on Android.
|
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
|
This pull request was successfully merged by @mrousavy in 87bae7f When will my fix make it into a release? | How to file a pick request? |
|
thanks guys!! 🖤 |


Summary:
While the new
installJSIBindings(..)/BindingsInstallerfunctionality allows you to synchronously set up stuff in the JS runtime before JS runs, there is no access to the JS CallInvoker, meaning you cannot really set up anything that uses callbacks or asynchronous code.Nitro needs this.
Changelog:
[IOS] [ADDED] - Add
CallInvokertoinstallJSIBindings(..)[ANDROID] [ADDED] - Add
CallInvokertoBindingsInstallerTest Plan:
In
SampleTurboModuleJSIBindings, we can now use theCallInvoker.