Can't resolve polyfill packages in project dependencies after updating webpack from v4 to v5

Viewed 805

After upgrading webpack to v5 in a project, attempting to build the project with webpack generates a swarm of errors, all with the format:

ERROR in ./node_modules/[dependency_name]/[file_name].js 28:13-30
Module not found: Error: Can't resolve '[polyfill_name]' in '.../node_modules/[dependency_name]'

I've found countless stackoverflow answers and guides (one even the official webpack guide) suggesting the solution is to use fallbacks in the webpack configuration file (because webpack v5 no longer includes the polyfills itself). In webpack.config.json, that is supposed to look something like:

module.exports = {
  
  ...configuration stuff...

  resolve: {
    fallback: { 
      util: require.resolve("util"),
      assert: require.resolve("assert"),
      buffer: require.resolve("buffer"),
      crypto: require.resolve("crypto-browserify"),
      http: require.resolve("stream-http"),
      https: require.resolve('https-browserify'),
      os: require.resolve("os-browserify/browser"),
      path: require.resolve("path-browserify"),
      stream: require.resolve("stream-browserify"),
      zlib: require.resolve("browserify-zlib") 
    }
  }
}

The missing polyfil plugins (https-browserify, os-browserify/browser, etc) must be installed as well, for example:

npm install path-browserify stream-browserify browserify-zlib etc etc

I have done both of these things, but the errors persist. I have also tried an alternative suggestion to use aliases rather than fallbacks; I have even gone so far as to install the polyfill plugins in the dependencies themselves in my project's node_modules folder:

cd node_modules/module_name && npm install https browserify

...All to no avail. I see countless other people who had these errors confirm that they resolved the errors with these strategies (except the last - installing the polyfills directly in the dependencies was a despearate last-ditch effort to see if I could make it work somehow).

Clearly I must be doing something wrong, because, as I mentioned, nobody else seems to be having issues once they implement the given solution. Here is my webpack configuration:

const path = require("path");
const CopyPlugin = require('copy-webpack-plugin');
var webpack = require('webpack');

const HtmlWebPackPlugin = require("html-webpack-plugin");

const htmlPlugin = new HtmlWebPackPlugin({
  inject: false,
  template: "./src/main/index.html",
  filename: "./index.html"
});

module.exports = {
  name: "Stress Tester",
  entry: "./src/main/index.js",
  output: {
    path: path.resolve(__dirname, "browser_build"),
    filename: "stress_tester.dist.js"
  },
  resolve: {
    fallback: { 
      util: require.resolve("util"),
      assert: require.resolve("assert"),
      buffer: require.resolve("buffer"),
      crypto: require.resolve("crypto-browserify"),
      http: require.resolve("stream-http"),
      https: require.resolve('https-browserify'),
      os: require.resolve("os-browserify/browser"),
      path: require.resolve("path-browserify"),
      stream: require.resolve("stream-browserify"),
      zlib: require.resolve("browserify-zlib") 
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        type: "javascript/auto",
        use: {
          loader: "babel-loader",
          options: {
            cacheDirectory: false,
            presets: [
              [
                '@babel/preset-env',
                {
                  targets: {
                    esmodules: true,
                  },
                },
              ],
            ],
          }
        }
      },
      {
        // Preprocess your css files
        // you can add additional loaders here (e.g. sass/less etc.)
        test: /\.css$/,
        exclude: /node_modules/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(jpe?g|png|gif)$/,
        use: [{
          loader: 'file-loader',
          /*
          options: {
            name: '[name].[ext]',
            outputPath: 'img/',
            publicPath:'img/'
          }
          */
        }]
       }
    ]
  },
  devtool: 'source-map',
  externals: ['worker_threads','ws','perf_hooks', 'child_process'], // exclude nodejs
  resolve: {
    symlinks: false,
    alias: {
      "fs": "html5-fs"
    },
    extensions: ['.js', '.jsx', '.css', '.json', 'otf', 'ttf', 'eot', 'svg'],
    modules: [
      'node_modules'
    ]
  },
  cache: true,
  context: __dirname,
  devServer: {
    devMiddleware: {
      publicPath: './browser_build',
      writeToDisk: true,
    }
  },
  plugins: [
    htmlPlugin,
    new CopyPlugin({
      patterns: [
        { from: path.resolve("node_modules/monero-javascript/dist"), to: path.resolve("browser_build") },
      ],
    }),
  ],
};

What am I missing?

1 Answers

This is a non-trivial migration, so it cannot be said that my additions will definitely help, but at least an extra chance.

There is a specific error for some cases regarding mjs:

const rules = [{
  test: /\.m?js/,
  resolve: {
    fullySpecified: false,
  },

Initial idea from the CRA migration: https://github.com/duplotech/create-react-app/commit/d0be703d40cd4bc32cd91128ba407a138c608243

const plugins = [
  new webpack.ProvidePlugin({
    process: 'process/browser.js',
    Buffer: ['buffer', 'Buffer'],
  }),

And non-significant fallbacks (for nodejs-thift client initially):

    alias: {
      http: require.resolve("stream-http"),
      https: require.resolve("https-browserify"),
      path: require.resolve("path-browserify"),
      crypto: require.resolve("crypto-browserify"),
      util: require.resolve("util"),
      buffer: require.resolve("buffer"),
      zlib: require.resolve("zlib-browserify"),
      stream: require.resolve("stream-browserify"),
      constants: require.resolve("constants-browserify"),
      process: require.resolve('process'),
    },
    fallback: {
      events: false ,
      child_process: false,
      fs: false,
      net: false,
      tls: false,
    },
  },
  externals: {
    bufferutil: 'commonjs bufferutil',
    'utf-8-validate': 'commonjs utf-8-validate',
  },
Related