How to use packages that depend on Node.js core modules in React Native.
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')
).
The best solution to running Node core modules in React Native is a
built-in React Native Packager configuration option: extraNodeModules
.
This little-known and undocumented feature allows
specifying modules that should be globally available as Node core
modules. To use this configuration option, add a rn-cli.config.js
file
in the root directory of your React Native project:
module.exports = {
extraNodeModules: {
crypto: require('react-native-cyrpto'),
},
};
For extra convenience, you can use the [node-libs-browser][] package to make all modules available:
module.exports = {
extraNodeModules: require('node-libs-browser'),
};
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 ReactNativify's global.js
for an example of doing this.