🔑

React Native で Unable to resolve module crypto の対処法

2021/11/05に公開

背景

現在関わっているプロジェクトでは monorepo を採用しており
React, React Native, Node.js などの複数のパッケージがある状態になっており、双方で使いたい処理などは共通パッケージに置いています。

今回共通パッケージに crypto.createCipheriv を使うファイルを置いたところ、React Native でエラーが出る状態になりました。

https://dev.classmethod.jp/articles/node-js_encryption/

エラーログ

error: Error: Unable to resolve module crypto from .../crypto.ts:
crypto could not be found within the project or in these directories:
  ../../node_modules

If you are sure the module exists, try these steps:
 1. Clear watchman watches: watchman watch-del-all
 2. Delete node_modules and run yarn install
 3. Reset Metro's cache: yarn start --reset-cache
 4. Remove the cache: rm -rf /tmp/metro-*
> 1 | import crypto from "crypto";

原因

React Native は Node.js で動いてるのではなく Hermes や JavaScript Core などの JavaScript エンジンを使っているため Node.js 内蔵のモジュールは動作をしないということです。共通のパッケージでは crypto を使用していたため上記のエラーが出ました。

対応の調査

  • crypto-js

    • npm の暗号化用のライブラリである crypto-js で crypto で書いていたコードをを代替できないかを調査しましたが crypto で使っていたcreateCipherivなどのメソッドが使うことができませんでした。
  • react-native-crypto

    • react-native-cryptoではrn-nodeifyを使ってセットアップするのですが、rn-nodeifynode_modulesの中を書き換える仕組みな為、monorepo でうまく動きませんでした。

解決方法

react-native-crypto にあった issue を参考に、metro.config.js内のextraNodeModules
crypto-browserify を追加する
ことで crypto が使用できるようになり解決しました
https://github.com/tradle/react-native-crypto/issues/46

    resolver: {
      extraNodeModules: {
        crypto: require.resolve("crypto-browserify"),
        stream: require.resolve("readable-stream"),
      },
    },

crypto-browserifyの内部でstreamを使用しているのでreadable-streamも追加する必要があります

今回はreact-native-cryptoではなく、crypto-browserifyを使いました。react-native-crypto ではreact-native-randombyteを導入する必要があるのですが、ネイティブモジュールを使っているため、pod installなどをする必要がある分、パフォーマンスは優れてるものがあると思われます。

まとめ

React Native crypto などのワードで検索をしても色々なやり方があったり、古い情報があったりして、解決するのに苦労しました。Node.js の crypto を React Native を使うことなどがあれば参考になれればと思います。

Discussion