How To: React Native w/ Web3 + 0x.js + 0xConnect

Abe
3 min readFeb 23, 2018

--

web3 and 0x.js were designed to work in a web browser and in node.js. react-native is missing several libraries that node.js includes (like crypto). Also, metro, the react-native dependency bundler, does some up-front magic to gather a list of dependencies, which makes dynamically constructed require statements impossible.

To get things working, there was 1 big decision to make:

  • web3 1.x or 0.20.x?

And 2 bugs to fix:

  • How to get beyond unable to resolve module errors.
  • How to overcome the Cannot find variable: self error.

TLDR

Several node.js libraries are missing in react-native and isomorphic-fetch doesn’t work well with react-native. To get it working, follow these steps:

  • npm i -S web3@0.20.5 (Do not use web3@1.0).
  • npm i -S abec/node-libs-react-native.
  • Add the following to rn-cli.config.js:
const extraNodeModules = require(“node-libs-react-native”);
module.exports = {
extraNodeModules
};
  • Add the following to the top of your root index.js file:
import “node-libs-react-native/globals”;
  • Add the following config to your package.json under the scripts section:
“prepare”: “npm run patch”,
“patch”: “find ./node_modules -name fetch-npm-browserify.js -print -exec sed -i.bk 's/self/global/g' {} \\;”

Problem: Web3 1.0 vs. 0.20.x

The way web3 version 1.0 manages dependencies differs greatly from 0.20.x. It splits itself up into several packages and ties them together using lerna. Also, some of dependencies are dynamically constructed, which conflicts with metro’s dependency gathering process.

Solution: Use 0.20.x

Install web3 version 0.20.5:

npm i -S web3@0.20.5

NOTE: The latest 1.x line seems to be working at first glance. 0x is still using 0.20.x though.

Problem: Unable To Resolve Module Errors

If you try to use web3or 0x.js in react-native, the first error you’ll encounter is:

bundling failed: Error: Unable to resolve module `crypto` from `…`: Module does not exist in the module map

react-native doesn’t include a crypto library (as well as several other libraries).

Solution: Use node-libs-react-native

Polyfills for the required modules exist and are aggregated in a library called node-libs-react-native. This library includes everything necessary to get web3 working, with the exception of vm. Without vm the following error comes up:

error: bundling failed: Error: Unable to resolve module `vm` from `.../node_modules/asn1.js/lib/asn1/api.js`: Module does not exist in the module map

vm is actually optional in asn1, but metro pulls it in when it builds its dependency list. The build process errors accordingly. So, I forked that github repo and added vm-browserify.

Here are steps to get this working:

  1. Run npm i -S abec/node-libs-react-native.
  2. Add the following to rn-cli.config.js:
const extraNodeModules = require(“node-libs-react-native”);
module.exports = {
extraNodeModules
};

3. Add the following to the top of your root index.js file:

import “node-libs-react-native/globals”;

Problem: Cannot Find Variable: Self

0x connect has a dependency on isomorphic-fetch, which does not work in react-native. When included, it throws this error:

Cannot find variable: self

isomorphic-fetch includes implementations for browser and node.js. The browser implementation, which is the one included when using react-native, has the following code:

// the whatwg-fetch polyfill installs the fetch() function 
// on the global object (window or global)
//
// Return that as the export for use in Webpack, Browserify etc. require(‘whatwg-fetch’);
module.exports = self.fetch.bind(self);

react-native has no sense of self and will not be able to include this library.

Solution: Edit The File Before Running (Best)

The fetch-npm-browserify.js file can be modified to replace self with global:

sed -i.bk ‘s/self/global/g’ ./node_modules/@0xproject/connect/node_modules/isomorphic-fetch/fetch-npm-browserify.js

To make this part of your build process, add the following config to your package.json under the scripts section:

“prepare”: “npm run patch”,
“patch”: “find ./node_modules -name fetch-npm-browserify.js -print -exec sed -i.bk 's/self/global/g' {} \\;”

In the long term, this will probably be fixed by the 0x community.

Another Solution: Replace isomorphic-fetch With A Modified Implementation (Not Great)

The dependency management system for react-native can be hacked using rn-nodeify to replace a dependency across all other dependencies. You can replace isomorphic-fetch with your own version using this method. I thought this was even more hacky than the above solution, so I decided against it.

References

  1. http://0xproject.com/
  2. https://facebook.github.io/metro/
  3. https://medium.com/@aakashns/using-core-node-js-modules-in-react-native-apps-64acd4d07140
  4. https://gist.github.com/parshap/e3063d9bf6058041b34b26b7166fd6bd
  5. https://github.com/0xProject/0x.js/issues/342
  6. https://gist.github.com/dougbacelar/29e60920d8fa1982535247563eb63766
  7. https://github.com/ethereum/web3.js/issues/1022#issuecomment-345640178

--

--