React + webpack5 で Web3 するメモ


webpack5 にしたら動かなくなった

create-react-app した React で、Metamask を扱う案件にて、webpack を 4 系から 5 系に上げたら、動かなくなったので、解決した。

Metamask の処理は、大雑把にまとめると、暗号化したり、復号化したり、Account や Key を Request したり、Transaction を作ったり流したりする。だいたいは、ethereum.request の諸々の API を叩くことで、実現できるが、暗号化で、以下のようなことをすることがある。

const ethUtil = require('ethereumjs-util');

const encryptedMessage = ethUtil.bufferToHex(
  Buffer.from(
    JSON.stringify(
      sigUtil.encrypt({
        publicKey: encryptionPublicKey,
        data: 'hello world!',
        version: 'x25519-xsalsa20-poly1305',
      })
    ),
    'utf8'
  )
);

こいつがなかなか手強い。

解決したい問題点

  1. eject したくない
  2. Node.js の polyfill が自動で入らなくなった
  3. source-map-loader が失敗する

ググると、諦めて webpack 4 系を使えというのがほとんどだが、そろそろ何とかならないものかとチャレンジしてみた次第。

検証環境

  • react: 18.0.0
  • react-scripts: 5.0.0
  • ethereumjs-util: 7.1.4
  • @metamask/eth-sig-util: 4.0.0

Eject せずに webpack.confg.js をいじる

react-app-rewired を利用した。

使い方は、書いてあるとおりで、インストールして、config-overrides.js を用意して、package.json の scripts の部分を書き換えるだけ。特につまづきポイントはなかった。

Node.js の Polyfill

入らなくなったものは、node-libs-browser にまとまっている。build すると、これがダメ、あれがダメと言われるので、必要なものをインストールし、webpack.config に Alias を設定していけば良い。

Webpack5でReactのプロジェクトをビルドしたら一生エラーが出続けた話

こんな感じで。
ただ、インストールする(今後管理する)パッケージが多いので、嫌だなと思っていたところ、全部入りのパッケージがあったので、それを使うことにした。

node-polyfill-webpack-plugin

必要ないものまで入る(かもしれない)が、スッキリするのでこっちの方が良かろうという判断。インストールし、config-overrides.js を以下のようにする。

config-overrides.js
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

module.exports = function override(config, env) {
  if (!config.plugins) {
    config.plugins = [];
  }
  config.plugins.push(
    new NodePolyfillPlugin({
      excludeAliases: ['console'],
    })
  );
  return config;
};

これでだいたい解決するが、Buffer のエラーが消えないので、それを解決する。

config-overrides.js
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const webpack = require('webpack');

module.exports = function override(config, env) {
  if (!config.plugins) {
    config.plugins = [];
  }
  config.plugins.push(
    new NodePolyfillPlugin({
      excludeAliases: ['console'],
    })
  );
  config.plugins.push(
    new webpack.ProvidePlugin({
      Buffer: ['buffer', 'Buffer'],
    })
  );
  return config;
};

これで、ビルドはできるようになる。

source-map-loader の Warning を無視する

ethereumjs-util, eth-sig-util などの Map できないという Warning が出るが、動くので無視する。

fix: ignore webpack warnings by source-map-loader #11752

create-react-app のこのプルリクが merge されるまでは、.envGENERATE_SOURCEMAP=false を追加しておく。merge されたら削除する。

.env
GENERATE_SOURCEMAP=false

これで、気持ちよく動くようになった。

まとめ

インストールしたもの:

  • react-app-rewired : 2.2.1
  • node-polyfill-webpack-plugin : 1.1.4

追加・修正したファイル:

├── build/
├── node_modules/
├── public/
├── src/
├── package.json
├── tsconfig.json
├── config-overrides.js ← 追加した
├── .env ← 編集した
└── yarn.lock

Metamask じゃなくても、だいたい似たような方針で解決できるんじゃないでしょうか。

おしまい。