Skip to content

Commit 3f63ccf

Browse files
kraenhansenCopilot
andauthored
Update docs on usage (#216)
* Update docs * Update docs/USAGE.md Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent 5903eca commit 3f63ccf

File tree

3 files changed

+59
-21
lines changed

3 files changed

+59
-21
lines changed

docs/ANDROID.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@
44

55
Because we're using a version of Hermes patched with Node-API support, we need to build React Native from source.
66

7+
Follow [the React Native documentation on how to build from source](https://reactnative.dev/contributing/how-to-build-from-source#update-your-project-to-build-from-source).
8+
9+
In particular, you will have to edit the `android/settings.gradle` file as follows:
10+
11+
> ```diff
12+
> // ...
13+
> include ':app'
14+
> includeBuild('../node_modules/@react-native/gradle-plugin')
15+
>
16+
> + includeBuild('../node_modules/react-native') {
17+
> + dependencySubstitution {
18+
> + substitute(module("com.facebook.react:react-android")).using(project(":packages:react-native:ReactAndroid"))
19+
> + substitute(module("com.facebook.react:react-native")).using(project(":packages:react-native:ReactAndroid"))
20+
> + substitute(module("com.facebook.react:hermes-android")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))
21+
> + substitute(module("com.facebook.react:hermes-engine")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))
22+
> + }
23+
> + }
24+
> ```
25+
26+
To download our custom version of Hermes, you need to run from your app package:
27+
28+
```
29+
npx react-native-node-api vendor-hermes
30+
```
31+
32+
This will print a path which needs to be stored in `REACT_NATIVE_OVERRIDE_HERMES_DIR` to instruct the React Native Gradle scripts to use it.
33+
34+
This can be combined into a single line:
35+
736
```
837
export REACT_NATIVE_OVERRIDE_HERMES_DIR=`npx react-native-node-api vendor-hermes --silent`
938
```

docs/HOW-IT-WORKS.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,6 @@ module.exports = require("react-native-node-api").requireNodeAddon(
3333
> In the time of writing, this code only supports iOS as passes the path to the library with its .framework.
3434
> We plan on generalizing this soon 🤞
3535
36-
### A note on the need for path-hashing
37-
38-
Notice that the `requireNodeAddon` call doesn't reference the library by it's original name (`prebuild.node`) but instead a name containing a hash.
39-
40-
In Node.js dynamic libraries sharing names can be disambiguated based off their path on disk. Dynamic libraries added to an iOS application are essentially hoisted and occupy a shared global namespace. This leads to collisions and makes it impossible to disambiguate multiple libraries sharing the same name. We need a way to map a require call, referencing the library by its path relative to the JS file, into a unique name of the library once it's added into the application.
41-
42-
To work around this issue, we scan for and copy any library (including its entire xcframework structure with nested framework directories) from the dependency package into our host package when the app builds and reference these from its podspec (as vendored_frameworks). We use a special file in the xcframeworks containing Node-API modules. To avoid collisions we rename xcframework, framework and library files to a unique name, containing a hash. The hash is computed based off the package-name of the containing package and the relative path from the package root to the library file (with any platform specific file extensions replaced with the neutral ".node" extension).
43-
4436
## Transformed code calls into `react-native-node-api`, loading the platform specific dynamic library
4537

4638
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.

docs/USAGE.md

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ The app developer has to install both `calculator-lib` as well as `react-native-
1717
The reason for the latter is a current limitation of the React Native Community CLI which doesn't consider transitive dependencies when enumerating packages for auto-linking.
1818

1919
> [!WARNING]
20-
> It's important to match the exact version of the `react-native-node-api` declared as peer dependency by `calculator-lib`.
20+
> It's important to match the version range of the `react-native-node-api` declared as a peer dependency by `calculator-lib`.
2121
22-
For the app to resolve the Node-API dynamic library files, the app developer must update their Metro config to use a `resolveRequest` function exported from `react-native-node-api`:
22+
For the app to resolve the Node-API dynamic library files, the app developer must update their Babel config to use a `requireNodeAddon` function exported from `react-native-node-api`:
2323

2424
```javascript
25-
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
26-
const nodeApi = require("react-native-node-api/metro-config");
27-
module.exports = mergeConfig(getDefaultConfig(__dirname), {
28-
resolver: { resolveRequest: nodeApi.resolveRequest },
29-
});
25+
module.exports = {
26+
presets: ["module:@react-native/babel-preset"],
27+
plugins: ["module:react-native-node-api/babel-plugin"], // 👈 This needs to be added to the babel.config.js of the app
28+
};
3029
```
3130

3231
At some point the app code will import (or require) the entrypoint of `calculator-lib`:
@@ -121,18 +120,36 @@ NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) {
121120
}
122121
```
123122
124-
### Build the prebuilt binaries
123+
```cmake
124+
# CMakeLists.txt
125125
126-
```
127-
npx react-native-node-api build ./addon.c
126+
cmake_minimum_required(VERSION 3.15...3.31)
127+
project(addon)
128+
129+
add_compile_definitions(-DNAPI_VERSION=4)
130+
131+
file(GLOB SOURCE_FILES "addon.c")
132+
133+
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})
134+
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
135+
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_JS_INC})
136+
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_JS_LIB})
137+
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
138+
139+
if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)
140+
# Generate node.lib
141+
execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})
142+
endif()
128143
```
129144

130-
This is a shorthand command which generates a CMake project from the single source-file and prebuilds for both the Apple and Android platforms. See the [CLI documentation](./CLI.md) for more information on the options available and [documentation on prebuilds](./PREBUILDS.md) for the specifics on their format and structure.
145+
### Build the prebuilt binaries
131146

132-
<!-- TODO: Add a listing of the files produced when running command: Some temp (cached) CMakeList.txt, the CMake project dir, 2x platform specific prebuild directories -->
147+
```
148+
npx cmake-rn
149+
```
133150

134151
### Load and export the native module
135152

136153
```javascript
137-
module.exports = require("./prebuild.node");
154+
module.exports = require("./build/Release/addon.node");
138155
```

0 commit comments

Comments
 (0)