This document will outline what happens throughout the various parts of the system, when the app calls the add method on the library introduced in the "usage" document.
Everything starts from the consuming app importing the calculator-lib.
Metro handles the resolution and the calculator-lib's entrypoint is added to the JavaScript-bundle when bundling.
calculator-lib does require("./prebuild.node") which is transformed into a call into the host TurboModule
The library has a require call to a .node file, which would normally not have any special meaning:
module.exports = require("./prebuild.node");Since the app developer has added the react-native-node-api/babel-plugin to their Babel configuration, the require statement gets transformed when the app is being bundled by Metro, into a requireNodeAddon call on our TurboModule.
The generated code looks something like this:
module.exports = require("react-native-node-api").requireNodeAddon(
"calculator-lib--prebuild",
);Note
In the time of writing, this code only supports iOS as passes the path to the library with its .framework. We plan on generalizing this soon 🤞
The native implementation of requireNodeAddon is responsible for loading the dynamic library and allow the Node-API module to register its initialization function, either by exporting a napi_register_module_v1 function or by calling the (deprecated) napi_module_register function.
In any case the native code stores the initialization function in a data-structure.
The initialization function of a Node-API module expects a node_env, which we create by calling createNodeApiEnv on the jsi::Runtime.
An exports object is created for the Node-API module and both the napi_env and exports object is passed to the Node-API module's initialization function and the third party code is able to call the Node-API free functions:
- The engine-specific functions (see js_native_api.h) are implemented by the
jsi::Runtime(currently only Hermes supports this). - The runtime-specific functions (see node_api.h) are implemented by
react-native-node-api.
When the exports object is populated by calculator-lib's Node-API module, control is returned to react-native-node-api which returns the exports object to JavaScript, with the add function defined on it.
import { add } from "calculator-lib";
console.log("1 + 2 =", add(1, 2));Now that the app's JavaScript call the add function, the JavaScript engine will know to call the associated native function, which was setup during the initialization of the Node-API module and the native Add function is executed and control returned to JavaScript again.