Open RSNara opened 4 years ago
Adding some of the people at MSFT we've discussed this with: @stmoy, @acoates-ms
Thanks for submitting your issue. Please run react-native info
in your terminal and copy the results into your issue description after "React Native version:". If you have already done this, please disregard this message.
👉 Click here if you want to take another look at the Bug Report issue template.
Curious, it looks like there is a need to abstract away from the jsi::*
objects to have something that's more universal / could theoretically work against more than just Hermes but at the same time much of the todo list seems to simply the continued used of jsi::*
objects.
Is the intent here to create a more generic way to create modules that do not care about the underlying JS engine? As that is something I am also interested in doing :)
Curious, it looks like there is a need to abstract away from the jsi:: objects to have something that's more universal / could theoretically work against more than just Hermes but at the same time much of the todo list seems to simply the continued used of jsi:: objects.
Your C++ TurboModule shouldn't have to know about the JS VM. But this doesn't mean that we stop using jsi::* objects. We need them to expose the TurboModule to JS. @KrisSiegel , does that answer your question?
it looks like TurboModules are currently coupled to STL types which makes the APIs non ABI-safe, thus hindering reuse-via-binary, are there plans to address this?
This issue needs to be prioritized for https://github.com/realm/realm-js/issues/2455 . It's a huge blocker
@shergin @mdvacca @JoshuaGross @hramos @fkgozali Sorry for the random ping.
Any chance of seeing any progress on this issue? It is apparently preventing RealmJS updating their module to get Hermes support going. https://github.com/realm/realm-js/issues/2455#issuecomment-703760988
+1 support for realmjs with turbomodule
I know this is an old issue and it seems like C++ TurboModules have matured since then (nice work!), but I've been struggling a bit with the setup.
I'm making react-native-mmkv a C++ TurboModule (feat/turbomodule
branch) as it only has one line of platform specific code, but I stumbled upon a few things:
CMakeLists.txt
. The one provided by the example and the documentation don't build for me
In file included from /Users/mrousavy/Projects/react-native-mmkv/android/build/generated/source/codegen/jni/RNMmkvSpec-generated.cpp:11:
/Users/mrousavy/Projects/react-native-mmkv/android/build/generated/source/codegen/jni/./RNMmkvSpec.h:13:10: fatal error: 'ReactCommon/JavaTurboModule.h' file not found
#include <ReactCommon/JavaTurboModule.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is there maybe a different example C++ TurboModule that I can take a look at?
I know this is an old issue and it seems like C++ TurboModules have matured since then (nice work!), but I've been struggling a bit with the setup.
I'm making react-native-mmkv a C++ TurboModule (
feat/turbomodule
branch) as it only has one line of platform specific code, but I stumbled upon a few things:
- On Android, autolinking just got supported in RN 0.74 and latest RN CLI by Nicola 👏
- On iOS, autolinking is not currently supported, so this is a blocker for me. :(
- On Android, I can't seem to correctly setup my
CMakeLists.txt
. The one provided by the example and the documentation don't build for meIn file included from /Users/mrousavy/Projects/react-native-mmkv/android/build/generated/source/codegen/jni/RNMmkvSpec-generated.cpp:11: /Users/mrousavy/Projects/react-native-mmkv/android/build/generated/source/codegen/jni/./RNMmkvSpec.h:13:10: fatal error: 'ReactCommon/JavaTurboModule.h' file not found #include <ReactCommon/JavaTurboModule.h> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is there maybe a different example C++ TurboModule that I can take a look at?
For future reference, an example of modules with C++ Autolinking is here: https://github.com/cortinico/reproducer-cxx-tm-autolinking/
If anyone encounters the same error as me make sure that you remove externalNativeBuild
from your library's build.gradle
file.
After all, the RN CodeGen project should build your C++ project, not your build.gradle.
Context
The C++ TurboModule system, unlike the ObjC and Java systems, is fairly immature. It has a lot of problems that need to be addressed, and gaps that need to be filled. Unfortunately, at Facebook, we only have a handful of C++ NativeModules. Additionally, there's no urgency to convert these NativeModules to C++-only TurboModules, because these NativeModules are already going through a bridging layer in the TurboModule system (i.e: we could turn off the old NativeModule system and still have these NativeModules fully functional). Therefore, it's difficult to prioritize development of the C++ TurboModule system internally.
For transparency, this is my focus in H1 2020:
With all the things on my plate this half, I find it unlikely that the C++ TurboModule system will be finished any time soon. So, this GitHub issue documents the work that's required to build out the C++ TurboModule system. If anyone is interested in taking ownership over this portion of the TurboModule project, please feel free to comment below. I'd love to work together and see this completed. 😁
Problem
This is currently the interface of our C++-only TurboModules:
There are a few problems with this API.
jsi::Runtime
is accessed safely. This simply isn't possible if we provide all C++-only TurboModules with access to thejsi::Runtime
.jsi::Function
,jsi::String
,jsi::Array
,jsi::Object
). First, this isn't a very clean API. Second, by design, many of these JSI objects (jsi::Function
especially) can't outlive thejsi::Runtime
(see the jsi.h). So, we should had C++-only TurboModules safe wrappers around these objects, so that the TurboModule framework can manage their lifecycles.Other things to think about:
CxxTurboModule
class, like we haveJavaTurboModule
, andObjCTurboModule
. If we want to make C++-only TurboModules more robust without bloating the codegen, this class would be necessary.How do I start?
There is currently only one pure C++ TurboModule:
SampleTurboCxxModule
. This TurboModule extends its "code-generated" specNativeSampleTurboCxxModuleSpecJSI
(the spec is really just hand-written). This spec directly extendsTurboModule
, as you can see here.CxxTurboModule
class and have it extend TurboModule. HaveNativeSampleTurboCxxModuleSpecJSI
extendCxxTurboModule
.NativeSampleTurboCxxModuleSpecJSI
. Feel free to modify the contents of the __hostFunctions in the codegen. Please look atRCTSampleTurboModuleSpec.mm
for an example of how we do this in iOS. Some of the responsibilities ofCxxTurboModule
:Object
type to? Should we usefolly::dynamic
?{| foo: bar |}
) to? In ObjC, we convert them to structs, since we know the type of each property.Array<T>
to? Should we just use an STL container?Promise
returns?resolve
and areject
lambda, like in ObjC, or do we pass in a "Promise" object, like we do in Android. Alternatively, should we leverage some STL data structure (std::promise
)?CxxTurboModule
constructor to accept a nativeCallInvoker
that dispatches work to a background thread.RCTModuleData
objects: code.DispatchMessageQueueThread
is the class our C++ NativeModules use to dispatch to the MessageQueue. Here's the async dispatch method: code.jsi::Function
s) on the JS Thread. This will require theCxxTurboModule
constructor to accept aCallInvoker
that dispatches work to the JS thread. Also, we'll have to store all thejsi::Function
objects passed from JS to C++ so that they can be invoked later by the JS thread. This presents an additional problem:jsi::Function
s (i.e: JS callbacks that were passed into C++ from JS) are destroyed. In iOS and Android, we accomplish this by usingLongLivedObjectCollection
, andCallbackWrapper
.LongLivedObjectCollection
is cleared when the runtime is destroyed.How do I test?
To test your changes, in RNTester on iOS, access the TurboModule in JS via
TurboModuleRegistry.get('SampleTurboCxxModule')
.