かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

😇 Webpack production のビルド時に Maximum call stack size exceeded エラーが発生する

Webpack を使って SCSS をコンパイルしているプロジェクトで久々に build したら下記のようなエラーが発生した

$ npx webpack --config ./webpack.config.js --mode production
…
webpack-fix-style-only-entries: removing js from style only module: js/css.js
(node:53965) [DEP_WEBPACK_CHUNK_HAS_ENTRY_MODULE] DeprecationWarning: Chunk.hasEntryModule: Use new ChunkGraph API
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:53965) [DEP_WEBPACK_CHUNK_ENTRY_MODULE] DeprecationWarning: Chunk.entryModule: Use new ChunkGraph API
(node:53965) [DEP_WEBPACK_MODULE_INDEX] DeprecationWarning: Module.index: Use new ModuleGraph API
...
ERROR in [entry] [initial] js/main.js
Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
    at ModuleGraph.getModuleGraphForModule (/path/to/node_modules/webpack/lib/ModuleGraph.js:842:32)
…
webpack 5.93.0 compiled with 1 error in 3219 ms

なんでや工藤…

version
  • webpack ^5.93.0

webpack.config

参考

// plugins
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const CompressionPlugin = require('compression-webpack-plugin');
// rules
const tsRules = require('./ts.rules');
const cssRules = require('./css.rules');

module.exports = (env, argv) => {
  const IS_PRODUCTION = argv.mode === 'production';

  return {
    mode: IS_PRODUCTION ? 'production' : 'development',
    devtool: !IS_PRODUCTION ? 'eval-source-map' : false, // https://webpack.js.org/configuration/devtool/
    entry: {
      main: `${DIR}/src/main.ts`,
      css: `${DIR}/scss/styles.scss`,
    },
    output: {
      path: OUTPUT_DIR,
      filename: 'js/[name].js',
    },
    plugins: [
      new FixStyleOnlyEntriesPlugin(),  // /js/css.js を出力しない
      IS_PRODUCTION &&
        new CompressionPlugin({
          test: /\.(css|scss|js)$/,
          algorithm: 'gzip',
          filename: '[path][base].gz',
        }),  // gzip 化 production mode 時のみ
      new MiniCssExtractPlugin({ filename: 'css/styles.css' }),  // `${OUTPUT_DIR}/css/styles.css` として出力
    ].filter(Boolean),
    resolve: { extensions: ['.ts', '.js'] },
    module: { rules: [ tsRules(), cssRules() ] },
  };
};

webpack-fix-style-only-entries プラグインが原因だった

CSS を webpack で build した際に空の css.js ファイルが作られてしまうのを防ぐためのプラグインが production mode でビルドした際のみエラーになっていたっのが原因だった

⚠️ The current package version is not compatible with webpack 5. There is a fork here that is compatible: https://github.com/webdiscus/webpack-remove-empty-scripts
cf. GitHub fqborges/webpack-fix-style-only-entries

Webpack 5 に適合してないので、Fork して作られた webpack-remove-empty-scripts を使ってくれとのこと。
※ webpack-remove-empty-scripts は webpack 5 に適合していているが、webpack 4 には適合して無く 4 の場合は引き続き webpack-fix-style-only-entries を使うのが良さそう

✅️ webpack-fix-style-only-entries を webpack-remove-empty-scripts に置き換える (webpack 5)

単純にプラグインを置き換えるだけで、同じ用に動作する

$ npm uninstall webpack-fix-style-only-entries
$ npm i -D webpack-remove-empty-scripts
webpack.config を修正する
// plugins
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
- const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
+ const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
const CompressionPlugin = require('compression-webpack-plugin');
…
module.exports = (env, argv) => {
  const IS_PRODUCTION = argv.mode === 'production';

  return {
    mode: IS_PRODUCTION ? 'production' : 'development',
    ...
    },
    plugins: [
-     new FixStyleOnlyEntriesPlugin(),  // /js/css.js を出力しない
+     new RemoveEmptyScriptsPlugin(),
      IS_PRODUCTION &&
        new CompressionPlugin({

プラグインを変更して production mode でのビルド (npx webpack --config ./webpack.config.js --mode production) がエラーにならず完了すれば OK

無事動作するようになってよかった
おわり ദ്ദിᐢ- ̫-ᐢ₎


[参考]