Skip to content

(Android) Native modules: compatability issues with node-gyp-build #57

@achou11

Description

@achou11

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-project

Will 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:

https://github.com/sodium-friends/sodium-native/blob/b4d2fec3262cb75a5d136046f56b5697606fe252/index.js

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

Wondering 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:

  1. Expose some kind of env variable that points to it, which I can use to patch each module using node-gyp-build to use the relevant native assets directory instead of __dirname. For example, sodium-native index file would look like:
const nativeBindingsDir = path.join(env.NATIVE_ASSETS_DIR, 'node_modules', 'sodium-native') 
module.exports = require('node-gyp-build')(nativeBindingsDir)
  1. A module that you can swap out with node-gyp-build that 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions