'plugin is not working in Webpack with React JS

I am creating a React JS app. I have installed terser-webpack-plugin to both try to compress my code as well as remove console.log() statements. However, it does not seem to be working.

I have installed the terser-webpack-plugin as follows:

npm install terser-webpack-plugin --save-dev

My webpack.config.js file looks like this:

const HtmlWebPackPlugin = require("html-webpack-plugin");
const CopyPlugin = require('copy-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            plugins: [
                "@babel/plugin-syntax-dynamic-import"
            ]
          }
        }
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader"
          }
        ]
      }
    ]
  },
  optimization: {
    minimize: true,
    minimizer: [
        new TerserPlugin({
                terserOptions: {
                        extractComments: 'all',
                        compress: {
                                drop_console: true
                        },

                }
        })
    ],
  },
  devtool: 'eval-source-map',
  plugins: [
    new HtmlWebPackPlugin({
      template: "./src/index.html",
      filename: "./index.html"
    }),
    new CopyPlugin([
      { from: 'src/css', to: 'css' }
    ])
  ]
};

However, when I run npm run build or npm run dev it does not seem to have any effect on the final file size and the comments are still there. What am I doing wrong?

As a side note, I am wondering how to make sure this only works for build and does not remove the comments on dev.



Solution 1:[1]

I discovered that the line devtool: 'eval-source-map', was preventing TerserPlugin from working. So, I have eliminated it from production. I have used winwiz1's example and modified it to fit my situation.

Something to note is that my package.json was using the following:

"scripts": {
    "dev": "webpack --mode development --watch",
    "build": "webpack --mode production"
}

So, rather than using my own environment variables I am using the mode parameter.

To use environment variables or parameters in webpack you need to modify it so that it is a function. See changes marked with comments below:

const HtmlWebPackPlugin = require("html-webpack-plugin");
const CopyPlugin = require('copy-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

//this was made as a function that returns a value
module.exports = (env, argv) => {

  //Here a constant isProduction is created that we can use as a switch to target code that should run either only in production or only in development mode.
  const isProduction = (argv.mode === "production")

  //Here is the return statement that returns the entire settings section as an object
  return {
    module: {
      rules: [
          // code removed for brevity  
      ]
    },
    //Will only run in production mode. Note the ... is the spread operator.
    ...(isProduction && {
      optimization: {
         //I removed the `minimize: true,` line as per winwiz1's suggestion
         minimizer: [
            new TerserPlugin({
                terserOptions: {
                        extractComments: 'all',
                        compress: {
                                drop_console: true
                        },
                }
             })
          ],
       },
    }),
    //Here we only set the devtool to eval-source-map if we are in development mode
    devtool: !isProduction && 'eval-source-map',
    plugins: [
      new HtmlWebPackPlugin({
        template: "./src/index.html",
        filename: "./index.html"
      }),
      new CopyPlugin([
        { from: 'src/css', to: 'css' }
      ])
    ]
  };
};

Solution 2:[2]

Using

optimization: {
    minimize: true,

tells webpack to create and use an instance of TerserPlugin with some default configuration options. Then you create another instance of the plugin:

new TerserPlugin({

It is better not to use minimize: true,

This configuration works:

...(isProduction && {
        minimizer: [
          new TerserPlugin({
            cache: false,
            parallel: true,
            sourceMap: false,     // set to true if debugging of production build needed
            terserOptions: {
              keep_classnames: false,
              mangle: true,
              compress: false,
              keep_fnames: false,
              output: {
                comments: false,
              }
            }
          })
        ]
      }),

I am wondering how to make sure this only works for build and does not remove the comments on dev.

Note how the boolean flag isProduction is used in the above code snippet. The flag is defined as follows:

const isProduction = (env && env.prod) ? true : false;

To make the flag work you call webpack as webpack in dev and webpack --env.prod for production build.

For the reference, the above code snippet is taken from here

Solution 3:[3]

You probably check your build file's extension! I'm struggling with this problem and solved it by adding test regex property to .js (default is .mjs)

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        test: /\.js(\?.*)?$/i, // you should add this property
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true,
            pure_funcs: ['console.log', 'console.info'], // Delete console
          },
        },
      }),
    ],
  },

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 winwiz1
Solution 3 Taehyun Hwang