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 useweb3@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 web3
or 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:
- Run
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
};
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
- http://0xproject.com/
- https://facebook.github.io/metro/
- https://medium.com/@aakashns/using-core-node-js-modules-in-react-native-apps-64acd4d07140
- https://gist.github.com/parshap/e3063d9bf6058041b34b26b7166fd6bd
- https://github.com/0xProject/0x.js/issues/342
- https://gist.github.com/dougbacelar/29e60920d8fa1982535247563eb63766
- https://github.com/ethereum/web3.js/issues/1022#issuecomment-345640178