|
|
@@ -0,0 +1,127 @@ |
|
|
# Running Node Modules in React Native |
|
|
|
|
|
*How to use packages that depend on Node.js core modules in React |
|
|
Native.* |
|
|
|
|
|
## 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][node-libs-browsers]. |
|
|
|
|
|
[node-libs-browsers]: https://github.com/webpack/node-libs-browser |
|
|
|
|
|
### 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. |
|
|
|
|
|
[react native packager]: https://github.com/facebook/react-native/tree/master/packager |
|
|
|
|
|
## 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. |
|
|
|
|
|
[react-native-crypto]: https://github.com/mvayngrib/react-native-crypto |
|
|
|
|
|
## 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][rn webpack], 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][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. |
|
|
|
|
|
[rn-nodeify]: https://github.com/mvayngrib/rn-nodeify |
|
|
[rn-nodeify readme]: https://github.com/mvayngrib/rn-nodeify#what-it-does |
|
|
[browser field]: https://github.com/defunctzombie/package-browser-field-spec |
|
|
|
|
|
### 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')`). |
|
|
|
|
|
[ReactNativify]: https://github.com/philikon/ReactNativify |
|
|
[transformer implementation]: https://github.com/philikon/ReactNativify/blob/master/transformer.js |
|
|
[packager's implementation]: https://github.com/facebook/react-native/blob/master/packager/transformer.js |
|
|
|
|
|
## `rn-cli.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 [little-known and undocumented feature][extraNodeModules] 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: |
|
|
|
|
|
```js |
|
|
module.exports = { |
|
|
extraNodeModules: { |
|
|
crypto: require('react-native-cyrpto'), |
|
|
}, |
|
|
}; |
|
|
``` |
|
|
|
|
|
For extra convenience, you can use the [node-libs-browser][] package to |
|
|
make all modules available: |
|
|
|
|
|
```js |
|
|
module.exports = { |
|
|
extraNodeModules: require('node-libs-browser'), |
|
|
}; |
|
|
``` |
|
|
|
|
|
[extraNodeModules]: https://github.com/facebookarchive/node-haste/pull/69 |
|
|
|
|
|
## 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 [ReactNativify's `global.js`][global] |
|
|
for an example of doing this. |
|
|
|
|
|
[global]: https://github.com/philikon/ReactNativify/blob/master/global.js |