Search code examples
javascriptreactjswebpackelectron

Porting webapck from webpack 4.29.6 to 5.93.0


I'm trying to upgrade my application in electron, specifically from webpack 4.29.6 to 5.93.0, but I'm running into a problem that I can't solve. The error during compilation is this:

[webpack-cli] TypeError: Cannot read properties of undefined (reading 'tapPromise')
    at ESLintWebpackPlugin.apply (..sources\webapp\node_modules\eslint-webpack-plugin\dist\index.js:63:26)
    at exports.createResolver (..sources\webapp\node_modules\enhanced-resolve\lib\ResolverFactory.js:695:11)
    at ResolverFactory._create (..\sources\webapp\node_modules\webpack\lib\ResolverFactory.js:135:12)
    at ResolverFactory.get (..\sources\webapp\node_modules\webpack\lib\ResolverFactory.js:116:28)
    at NormalModuleFactory.getResolver (..\sources\webapp\node_modules\webpack\lib\NormalModuleFactory.js:1302:31)
    at defaultResolve (..\sources\webapp\node_modules\webpack\lib\NormalModuleFactory.js:759:35)
    at ..\sources\webapp\node_modules\webpack\lib\NormalModuleFactory.js:828:10
    at Hook.eval [as callAsync] (eval at create (..\sources\webapp\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:7:1)
    at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (..\sources\webapp\node_modules\tapable\lib\Hook.js:18:14)
    at ..\sources\webapp\node_modules\webpack\lib\NormalModuleFactory.js:340:24

this is my webpack-app.config.js:

    'use strict';

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const paths = require('./config/paths');
const getClientEnvironment = require('./config/env');

// Webpack uses `publicPath` to determine where the app is being served from.
const publicPath = paths.servedPath;
const shouldUseRelativeAssetPaths = publicPath === './';
const publicUrl = publicPath.slice(0, -1);
const env = getClientEnvironment(publicUrl);

// Note: defined here because it will be used more than once.
const cssFilename = 'static/css/[name].css';

module.exports = {
  mode: 'development',
  bail: true,
  devtool: 'cheap-module-source-map',
  entry: [require.resolve('./src/polyfills'), 'babel-polyfill', paths.appIndexJs],
  output: {
    path: paths.appBuild,
    filename: 'static/js/[name].js',
    chunkFilename: 'static/js/[name].chunk.js',
    publicPath: publicPath,
    devtoolModuleFilenameTemplate: info => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/')
  },
  resolve: {
    modules: ['node_modules', paths.appNodeModules].concat(
      process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
    ),
    extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx'],
    alias: {
      'react-native': 'react-native-web'
    },
    plugins: [
      new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
      new ESLintWebpackPlugin({ extensions: ['js', 'jsx'] }),
    ]
  },
  module: {
    strictExportPresence: true,
    rules: [
      {
        test: /\.(js|jsx)$/,
        enforce: 'pre',
        use: [
          {
            options: {
              formatter: require.resolve('react-dev-utils/eslintFormatter'),
              eslintPath: require.resolve('eslint')
            },
            loader: 'eslint-webpack-plugin',
          }
        ],
        include: paths.appSrc
      },
      {
        oneOf: [
          {
            test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
            type: 'asset',
            parser: {
              dataUrlCondition: {
                maxSize: 10000, // 10kb
              },
            },
            generator: {
              filename: 'static/media/[name].[hash][ext]'
            }
          },
          {
            test: /\.svg$/,
            use: [
              {
                loader: '@svgr/webpack',
                options: {
                  svgoConfig: {
                    plugins: [
                      { removeViewBox: false },
                      { cleanupIDs: false },
                      { prefixIds: false }
                    ]
                  }
                }
              },
              {
                loader: 'url-loader',
                options: {
                  limit: 10000,
                  name: 'static/media/[name].[hash].[ext]'
                }
              }
            ]
          },
          {
            test: /\.(js|jsx)$/,
            include: paths.appSrc,
            use: {
              loader: require.resolve('babel-loader'),
              options: {
                sourceMap: true
              }
            }
          },
          {
            test: /\.css$/,
            use: [
              "style-loader",
              "css-loader",
              {
                loader: "postcss-loader",
                options: {
                  postcssOptions: {
                    plugins: [
                      [
                        "postcss-preset-env",
                        {
                          // Options
                        },
                      ],
                    ],
                  },
                },
              },
            ],
          },
          {
            test: /\.(eot|otf|ttf|woff|woff2)$/,
            type: 'asset/resource',
            generator: {
              filename: 'static/media/[name].[hash][ext]'
            }
          },
          {
            type: 'asset/resource',
            exclude: [/\.js$/, /\.html$/, /\.json$/],
            generator: {
              filename: 'static/media/[name].[hash][ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: './index.html',
      inject: true,
      template: paths.appHtml,
      minify: {
        removeComments: false,
        collapseWhitespace: false,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true
      },
      templateParameters: {
        PUBLIC_URL: publicUrl
      }
    }),
    new webpack.DefinePlugin(env.stringified),
    new MiniCssExtractPlugin({
      filename: cssFilename
    }),
    new ESLintPlugin({
      extensions: ['js', 'jsx'],
      eslintPath: require.resolve('eslint'),
      formatter: require.resolve('react-dev-utils/eslintFormatter'),
    }),
    new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ })
  ],
  externals: {
    'electron-edge-js': 'commonjs2 electron-edge-js',
  },
  performance: {
    hints: false,
    maxEntrypointSize: 512000,
    maxAssetSize: 512000
  }
};

the versions of webpack, webpack-cli and eslint-webpack-plugin are: "webpack-cli": "^5.1.4" "webpack": "^5.93.0", "eslint-webpack-plugin": "^4.2.0",

Someone can help me? I have delete the node_modules and package.lock and reinstall all but without success


Solution

  • If you read the stack of your error, you can see that it is thrown by eslint-webpack-plugin (second line):

    at ESLintWebpackPlugin.apply (..sources\webapp\node_modules\eslint-webpack-plugin\dist\index.js:63:26)
    

    Now, if you do a quick search into the issues of this plugin, you will find that others people got the same error and created an issue: Cannot use with webpack ERROR in Cannot read property 'tapPromise' of undefined. Finally, if you read the comments in the issue thread, you can find the reason of the error:

    The problem was that plugin should not have been inside resolve.

    As per EslintWebpackPlugin docs, you should use the plugin like this:

    const ESLintPlugin = require('eslint-webpack-plugin');
    
    module.exports = {
      // ...
      plugins: [new ESLintPlugin(options)],
      // ...
    };