Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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.

@lucaszanella

This comment has been minimized.

Copy link

@lucaszanella lucaszanella commented Mar 21, 2018

I'm getting a very strange error about property being undefined: https://stackoverflow.com/questions/49398078/porting-nodejs-module-to-react-native-object-prototype-undefined

I tried both react nativify and extraNodeModules and both have the same result!

If you already experienced this, please help me :)

@habibalamin

This comment has been minimized.

Copy link

@habibalamin habibalamin commented Dec 20, 2018

Some versions of React Native configure this using metro.config.js, and the extraNodeModules key needs to be nested under a resolver key:

module.exports = {
  resolver: {
    extraNodeModules: {
      url: require.resolve('whatwg-url')
    }
  }
};
@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 18, 2019

I added a comment relevant to this gist here: philikon/ReactNativify#4 (comment)

@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 18, 2019

FYI the [node-libs-browser][] link is broken in this gist. If this were in a repo rather than a gist, I would make a PR to fix that.

@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 18, 2019

@parshap Also, now that extraNodeModules is documented, it would be nice to update this to reflect that.

Thanks for making this helpful gist!

@parshap

This comment has been minimized.

Copy link
Owner Author

@parshap parshap commented Dec 18, 2019

Updated! Thanks.

FWIW I have the node-libs-react-native library that should help with using extraNodeModules and I'd like it to be the source of truth for documentation on this approach. This gist is more historical. Would appreciate any help updating the documentation here: https://github.com/parshap/node-libs-react-native

@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 18, 2019

@parshap Noted! Thanks! Having the link over to that repo here is very helpful.

@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 18, 2019

@parshap Oh, and FYI this gist has pretty good SEO on google, so I think it's safe to assume most people will find this gist first before that repo.

I would suggest removing this line:

"not supporting require() calls with an expression (such as require('cyrp' + 'to'))."

...since ReactNativify does support that if you use the throwForNonStringLiteral setting

@parshap

This comment has been minimized.

Copy link
Owner Author

@parshap parshap commented Dec 18, 2019

Thanks! I vaguely remember trying to use throwForNonStringLiteral and still having issues with it, but I've added a mention of it to the gist.

I also added a link to the node-libs-react-native library to the top of the gist. Any help improving the documentation or implementation of node-libs-react-native would be greatly appreciated as I'm not currently working on any React Native projects myself.

@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 18, 2019

Thanks! One last thing to change in this gist: the second metro.config.js example is missing the nested resolver part.

@parshap

This comment has been minimized.

Copy link
Owner Author

@parshap parshap commented Dec 19, 2019

Ah thank you, fixed. I wish I could give others write access to gists!

@pcowgill

This comment has been minimized.

Copy link

@pcowgill pcowgill commented Dec 31, 2019

@parshap You could consider turning the gist into a link over to a repo that just has a README with the contents of this gist?

@mateus-oliveira

This comment has been minimized.

Copy link

@mateus-oliveira mateus-oliveira commented Jun 6, 2020

How I can import HTTPS lib with node-libs-react-native?

@parshap

This comment has been minimized.

@radelcom

This comment has been minimized.

Copy link

@radelcom radelcom commented Nov 27, 2020

please help! i am trying LDAPjs with RN and getting error with 'net' module even though 'netjs' is mocked in node-libs-react-native.

@joeyfigaro

This comment has been minimized.

Copy link

@joeyfigaro joeyfigaro commented Jan 15, 2021

@radelcom same

@radelcom

This comment has been minimized.

Copy link

@radelcom radelcom commented Jan 15, 2021

@joeyfigaro i managed to get the error solved. I used different packages and set it as a resolver under metro.config.js

I played around with react-native-tls and react-native-tcp-socket. However, if your LDAP server require sasl authentication, LDAP.js does not support it if im not mistaken.

extraNodeModules: { ...require('node-libs-react-native'), // net: require.resolve('react-native-tls'), //require.resolve('react-native-tcp-socket'), // tls: require.resolve('react-native-tls'), fs: require.resolve('react-native-fs'), },

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