React + webpack5 で Web3 するメモ

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

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

Metamask の処理は、大雑把にまとめると、暗号化したり、復号化したり、Account や Key を Request したり、Transaction を作ったり流したりする。だいたいは、[ethereum.request の諸々の API](https://docs.metamask.io/guide/rpc-api.html#table-of-contents) を叩くことで、実現できるが、暗号化で、以下のようなことをすることがある。

```typescript
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 したくない
1. Node.js の polyfill が自動で入らなくなった
1. 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](https://github.com/timarney/react-app-rewired) を利用した。

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

## Node.js の Polyfill

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

[Webpack5でReactのプロジェクトをビルドしたら一生エラーが出続けた話](https://qiita.com/issei_k/items/f33164a22b8c1dc74a09)

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

[node-polyfill-webpack-plugin](https://www.npmjs.com/package/node-polyfill-webpack-plugin)

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

```javascript: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 のエラーが消えないので、それを解決する。

```javascript: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](https://github.com/facebook/create-react-app/pull/11752)

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

```text:.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 じゃなくても、だいたい似たような方針で解決できるんじゃないでしょうか。

おしまい。