webpack 5 で「process is not defined」やコアモジュールの解決に失敗する
webpack 5 は Node.js コアモジュールの自動 polyfill をやめた。
ブラウザ向けビルドで process や crypto を参照すると未定義や解決失敗になる。
必要なものだけ resolve.fallback と ProvidePlugin で明示的に補う。
公開:
要約
Uncaught ReferenceError: process is not defined や Module not found: Error: Can't resolve 'crypto' が webpack 5 へ上げた直後に出るのは、webpack 5 が Node.js コアモジュールの自動 polyfill を廃止したためだ。
webpack 4 は crypto や stream を自動で browserify 版に差し替えていたが、5 では何も入らない。
必要なものだけを自分で補うのが正しい対処になる。
まずバンドルサイズを増やさない選択肢から検討する。
// webpack.config.js
module.exports = {
resolve: {
fallback: { fs: false, path: require.resolve("path-browserify") },
},
};よくある原因
- 自動 polyfill の廃止: webpack 5 はブラウザ向けビルドで Node.js コアモジュールを自動補完しない。移行ガイド(新しいタブで開く)にも、必要なら npm から互換モジュールを入れて自分で指定するよう書かれている。
- 依存パッケージが Node 前提: 自分のコードに
processが無くても、依存の内部がprocess.env.NODE_ENVを読んでいれば同じエラーになる。 - webpack 4 の設定が残っている:
node: { fs: 'empty' }は webpack 5 では機能しない。resolve.fallback.fs: falseに書き換える必要がある。 - サーバー専用コードの巻き込み: 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 のグローバルを注入する
process と Buffer はモジュールではなくグローバル変数として参照されるため、resolve.fallback だけでは解決しない。ProvidePlugin で注入する。
// webpack.config.js
const webpack = require("webpack");
module.exports = {
plugins: [
new webpack.ProvidePlugin({
process: "process/browser",
Buffer: ["buffer", "Buffer"],
}),
],
};process/browser は process パッケージに含まれるブラウザ向け実装で、別途インストールが必要になる。
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 自体が不要になる。