How to use HiveJs (or other modules referencing core Node.js modules) on React Native

image.png

As some of you may know, I am developing a Hive Keychain App for mobile using React Native (RN). @revo asked me how I managed to use Hive related modules on RN.

Although RN uses Javascript, some npm modules won't work directly because they use Node.js core modules such as assert and crypto.

It's a bit tedious to make it work, but I truly hope to see more mobile Application in our ecosystem, so I'm writing this tutorial hoping it will be of some help.

Babel to the rescue!

We will use Babel and rewrite-require preset to rewrite some of these modules to use React Native or browserified packages instead.

Let's see step by step how this is working out on a new project.

Step 1 : Create a new project

I will assume you already have your environment setup and that we are making a classic React Native project (no expo) :

npx react-native init [ProjectName]

Step 2 : Add Hivejs

Run

npm i @hiveio/hive-js --save

Let's try it out, on App.js, add the following lines after the imports :

import hivejs from '@hiveio/hive-js'

(async function () {
  console.log(await hivejs.api.getAccountsAsync(['stoodkev']));
})();

Try to run the App and bim! Error!

error: Error: Unable to resolve module `assert` from `node_modules/@hiveio/hive-js/lib/auth/memo.js`: assert could not be found within the project.

That's because React Native has no idea what assert or crypto modules are, since they are Node.js core modules.

Step 3 : Babel Config

Find your babel file, babel.config.js.
Note that the name might be slightly different such as .babelrc or .babel-cli.

Add the following lines to the existing config :

sourceMaps: true,
plugins: [
        [
            'rewrite-require',
            {
                aliases: {
                    crypto: 'react-native-crypto',
                    constants: 'constants-browserify',
                    dns: 'node-libs-browser/mock/dns',
                    domain: 'domain-browser',
                    fs: 'node-libs-browser/mock/empty',
                    http: 'stream-http',
                    https: 'https-browserify',
                    net: 'node-libs-browser/mock/net',
                    os: 'os-browserify/browser',
                    path: 'path-browserify',
                    pbkdf2: 'react-native-pbkdf2-shim',
                    querystring: 'querystring-es3',
                    stream: 'stream-browserify',
                    _stream_duplex: 'readable-stream/duplex',
                    _stream_passthrough: 'readable-stream/passthrough',
                    _stream_readable: 'readable-stream/readable',
                    _stream_transform: 'readable-stream/transform',
                    _stream_writable: 'readable-stream/writable',
                    sys: 'util',
                    timers: 'timers-browserify',
                    tls: 'node-libs-browser/mock/tls',
                    tty: 'tty-browserify',
                    vm: 'vm-browserify',
                    zlib: 'browserify-zlib',
                },
                throwForNonStringLiteral: true,
            },
        ],
    ],

Install the following dependencies :

npm i --save babel-plugin-rewrite-require events assert react-native-crypto stream react-native-randombytes vm-browserify process

Also add manually this dependency in package.json then npm install :

"react-native-pbkdf2-shim": "git+https://git@github.com/wswoodruff/react-native-pbkdf2-shim.git"

Step 4 : Add globals

If you try to run the code now you should see this error :

ExceptionsManager.js:76 Error: Buffer not supported in this environment. Use Node.js or Browserify for browser support.

Create a global.js file on the root of the project :

// Inject node globals into React Native global scope.
global.Buffer = require('buffer').Buffer;
global.process = require('process');
global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production';

// Needed so that 'stream-http' chooses the right default protocol.
global.location = {
  protocol: 'file:',
};

// Don't do this in production. You're going to want to patch in
// https://github.com/mvayngrib/react-native-randombytes or similar.
global.crypto = {
  getRandomValues(byteArray) {
    for (let i = 0; i < byteArray.length; i++) {
      byteArray[i] = Math.floor(256 * Math.random());
    }
  },
};

And import it from App.js :

import './global.js'

Step 5: Voila!

HiveJs should now be working and you should see my account info in your debugger.

If you are still getting errors, try cleaning the modules :

rm -rf node_modules && npm install && npx jetify

I uploaded my code to Github for reference, I hope this will help future Hive mobile devs ;)

If you have questions or encounter some issues, don't hesitate to ask me questions in the comment section.

Hive on!


@stoodkev
Hive Keychain PO
If you find my work valuable, please consider voting for my Witness

H2
H3
H4
3 columns
2 columns
1 column
14 Comments