Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dlrandy/d30ac0902be1b271035f3282abd7e45d to your computer and use it in GitHub Desktop.
Save dlrandy/d30ac0902be1b271035f3282abd7e45d to your computer and use it in GitHub Desktop.
Running Node Modules in React Native

Running Node Modules in React Native

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.js Core Modules

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.

Browsers

"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.

React Native

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.

Why

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.

Prior Work

There are several approaches to running Node core modules in React Native.

Webpack for 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

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

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).

metro.config.js and extraNodeModules

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'),
  },
};

Global Environment

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment