できない.dev

webpack 5 で「process is not defined」やコアモジュールの解決に失敗する

webpack 5 は Node.js コアモジュールの自動 polyfill をやめた。
ブラウザ向けビルドで processcrypto を参照すると未定義や解決失敗になる。
必要なものだけ resolve.fallbackProvidePlugin で明示的に補う。

公開:

要約

Uncaught ReferenceError: process is not definedModule not found: Error: Can't resolve 'crypto' が webpack 5 へ上げた直後に出るのは、webpack 5 が Node.js コアモジュールの自動 polyfill を廃止したためだ。
webpack 4 は cryptostream を自動で browserify 版に差し替えていたが、5 では何も入らない。

必要なものだけを自分で補うのが正しい対処になる。
まずバンドルサイズを増やさない選択肢から検討する。

// webpack.config.js
module.exports = {
  resolve: {
    fallback: { fs: false, path: require.resolve("path-browserify") },
  },
};

よくある原因

  1. 自動 polyfill の廃止: webpack 5 はブラウザ向けビルドで Node.js コアモジュールを自動補完しない。移行ガイド(新しいタブで開く)にも、必要なら npm から互換モジュールを入れて自分で指定するよう書かれている。
  2. 依存パッケージが Node 前提: 自分のコードに process が無くても、依存の内部が process.env.NODE_ENV を読んでいれば同じエラーになる。
  3. webpack 4 の設定が残っている: node: { fs: 'empty' } は webpack 5 では機能しない。resolve.fallback.fs: false に書き換える必要がある。
  4. サーバー専用コードの巻き込み: DB クライアントなどサーバー専用パッケージが、共通モジュール経由でブラウザ側の依存グラフに入っている。

解決策

1. 必要なコアモジュールだけ fallback を指定する

polyfill パッケージを入れ、resolve.fallback で対応付ける。

npm install --save-dev path-browserify stream-browserify buffer
// webpack.config.js
module.exports = {
  resolve: {
    fallback: {
      path: require.resolve("path-browserify"),
      stream: require.resolve("stream-browserify"),
      buffer: require.resolve("buffer/"),
    },
  },
};

crypto-browserify のように数百 KB になる polyfill もある。
全部入れる前に、本当にブラウザで必要かを確認したほうがよい。

2. process / Buffer のグローバルを注入する

processBuffer はモジュールではなくグローバル変数として参照されるため、resolve.fallback だけでは解決しない。ProvidePlugin で注入する。

// webpack.config.js
const webpack = require("webpack");
 
module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      process: "process/browser",
      Buffer: ["buffer", "Buffer"],
    }),
  ],
};

process/browserprocess パッケージに含まれるブラウザ向け実装で、別途インストールが必要になる。

3. 使わないモジュールは空にする

到達しないコードパスで参照されているだけなら、polyfill を入れずに false を指定してバンドルから外す。

// webpack.config.js
module.exports = {
  resolve: {
    fallback: { fs: false, child_process: false, net: false },
  },
};

webpack 4 の node: { fs: 'empty' } はこの書き方に置き換わった。
設定の対応関係は公式の node オプション(新しいタブで開く)にまとまっている。

4. ブラウザに持ち込まない

一番確実なのは、そもそも巻き込まないことだ。
サーバー専用の処理を別モジュールへ切り出し、ブラウザ側のエントリから参照しないようにする。
環境変数を渡したいだけなら DefinePlugin で定数として埋め込めば process 自体が不要になる。

この記事は役立ちましたか?