How to use packages that depend on Node.js core modules in React Native.
See the node-libs-react-native library as a convenience for implementing this method.
Node has several modules that are automatically available via
require()
: http
, crypto
, etc. While these modules are available
in Node, they are not automatically available in other environments
such as browsers and React Native.
"Node-style" code (using modules and require()
) that targets browsers
is usually compiled using tools such as Webpack or Browserify. These
compilers implement require()
and other functionality normally
available in Node but not browsers, including Node core modules
implemented for browser usage.
Similar to the browsers scenario, React Native compiles "Node-style" code to run in the React Native environment via the React Native Packager. The packager is similar to Webpack or Browserify, but with some minor differences, including having no official documentation or best practice for running Node core module.
Usually, there are React Native-specific counterparts to the Node core modules that provide the same functionality, e.g., react-native-crypto. So why does one need Node core modules to work in React Native? The answer is cross-platform code and the vast npm ecosystem. It's convenient to be able to use the same modules in React Native as in Node and browsers.
There are several approaches to running Node core modules in React Native.
While it's possible to use Webpack with React Native, it's not a widely used approach and as long as Facebook uses React Native Packager internally, React Native will work best with React Native Packager.
rn-nodeify works by editing all package.json
files in
node_modules
to add the react-native
field. Similar to the
browser
field in package.json
, the react-native
field tells the React Native Packager to substitute one modules with
another (e.g., crypto
with react-native-crypto
). rn-nodeify also
applies various other "hacks" to some sources files. See the rn-nodeify
readme for more information.
This approach is less than ideal because it involves editing files in
the node_modules
directory and must be run after every time
dependencies are changed.
ReactNativify documents how to use a custom React Native Packager
transformer and the [babel-plugin-rewrite-require
][babel rewrite]
Babel plugin to support Node core modules. While this solution is
robust, being wholly encapsulated by the packager without depending on
editing files in node_modules
, it's not ideal as it involves
maintaining a complicated transformer implementation and keeping it
up to date with [Packager's implementation][packager transformer].
babel-plugin-rewrite-require
also has slightly different behavior than
Webpack and Browserify, not supporting require()
calls with
an expression (such as require('cyrp' + 'to')
-- though this case can
be supported using the throwForNonStringLiteral
option).
The best solution to running Node core modules in React Native is a
built-in React Native Packager configuration option:
extraNodeModules
. This feature allows specifying
modules that should be globally available as Node core modules. To use
this configuration option, add a metro.config.js
file in the root
directory of your React Native project:
module.exports = {
resolver: {
extraNodeModules: {
crypto: require('react-native-cyrpto'),
},
},
};
For extra convenience, you can use the node-libs-react-native package to make all modules available:
module.exports = {
resolver: {
extraNodeModules: require('node-libs-react-native'),
},
};
While the above solution will make it possible to require()
Node core
modules, "Node-style" code also expects the global environment to be in
a specific state. The React Native global environment should be mutated
to meet these expectations. See node-libs-react-native/globals
for an example of doing this.
I added a comment relevant to this gist here: philikon/ReactNativify#4 (comment)