-
-
Notifications
You must be signed in to change notification settings - Fork 59
Description
Attempting to use some modules from the Holepunch ecosystem that have native counterparts but due to assumptions it makes about the project structure, a runtime error occurs related to trying to load the native module:
Error: No native build was found for platform=android arch=arm64 runtime=node abi=93 uv=1 armv=8 libc=glibc node=16.17.1
loaded from: /data/data/com.mapeonext/files/nodejs-projectWill use sodium-native as the example since this error is stemming from there, but this issue applies to any module that uses node-gyp-build for loading native bindings.
Noticed that sodium-native uses __dirname to tell node-gyp-build where to start looking for the native binding:
Unfortunately, in the context of a NodeJS Mobile React Native project, __dirname resolves to /data/data/com.myproject/files/nodejs-project (as seen in error message above)
This error comes from https://github.com/prebuild/node-gyp-build/blob/8419abba399ec01f28cfb02b207b659153052a69/node-gyp-build.js#L60
Their resolution strategy lives in https://github.com/prebuild/node-gyp-build/blob/8419abba399ec01f28cfb02b207b659153052a69/node-gyp-build.js#L62-L74
My understanding of the directory structure that NodeJS mobile creates for my application is generally as follows (other targets+archs omitted for brevity):
.
├── nodejs-assets/
│ └── nodejs-project/ # contains app code, no native modules should live here
│ ├── index.js
│ ├── loader.js
│ ├── node_modules/
│ └── package.json
├── nodejs-native-assets/ # contains native modules, separated by platform + architecture
│ └── nodejs-native-assets-arm64-v8a/
│ ├── dir.list
│ ├── file.list
│ └── node_modules/ # bindings for each native module should live here
│ └── sodium-native
│ └── build
│ └── Release
│ └── sodium.nodeWondering how NodeJS Mobile tells the application that it should look in the nodejs-native-assets/nodejs-native-assets-arm64-v8a/node_modules/... directory for loading native bindings.
Think there are a couple of potential solutions:
- Expose some kind of env variable that points to it, which I can use to patch each module using
node-gyp-buildto use the relevant native assets directory instead of__dirname. For example,sodium-nativeindex file would look like:
const nativeBindingsDir = path.join(env.NATIVE_ASSETS_DIR, 'node_modules', 'sodium-native')
module.exports = require('node-gyp-build')(nativeBindingsDir)- A module that you can swap out with
node-gyp-buildthat knows about the NodeJS mobile directory structure, which you would use with a bundler. This is similar to what @staltz has for Noderify: https://github.com/staltz/bindings-noderify-nodejs-mobile.
My guess is that 2 is probably a better solution because it wouldn't require patching every module. Only downside is that it assumes that you're using a bundler that allows you to swap out modules, which is recommended but not ideal to assume.
Environment info:
OS: macOS 14 (Sonoma)
NodeJS Mobile version: 16.17.10
NPM version: 8.19.4