Why compress images at build time?

Images often ship much larger than they need to be. Fixing that in your webpack build is straightforward with imagemin-webpack-plugin, which hooks image compression into the same bundle step that already handles your JavaScript and CSS.

This walkthrough assumes a project that already has webpack, webpack-cli, and imagemin-webpack-plugin installed. You might notice images being copied from images/ into dist/ by the existing config, but nothing is shrinking them yet.

Wire Imagemin into webpack

Start by declaring the plugin at the top of webpack.config.js:

const ImageminPlugin = require('imagemin-webpack-plugin').default;

Then register it as the last entry in the plugins[] array:

new ImageminPlugin()

At this point your config is complete for basic compression:

const ImageminPlugin = require('imagemin-webpack-plugin').default;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');

module.exports = {
  entry: './index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
     new CopyWebpackPlugin([{
       from: 'img/**/**',
       to: path.resolve(__dirname, 'dist')
     }]),
     new ImageminPlugin()
  ]
}

Run webpack to see what happens:

webpack --config webpack.config.js --mode development

Now try the production build:

webpack --config webpack.config.js --mode production

In production mode webpack flags oversized PNGs—even after the default compression pass. Development mode doesn't show this because it prioritizes build speed over these warnings.

Tune compression for specific formats

To quiet the PNG warning, pass an options object to ImageminPlugin() that targets PNGs with the Pngquant plugin:

{pngquant: ({quality: [0.5, 0.5]})}

The quality field takes a min and max between 0 (worst) and 1 (best). Setting both to 0.5 forces a uniform 50% quality. Your config now should resemble:

const ImageminPlugin = require('imagemin-webpack-plugin').default;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');

module.exports = {
  entry: './index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new CopyWebpackPlugin([{
        from: 'img/**/**',
        to: path.resolve(__dirname, 'dist')
    }]),
    new ImageminPlugin({
      pngquant: ({quality: [0.5, 0.5]}),
      })
  ]
}

JPEGs need the same attention. The default imagemin-jpegtran doesn't let you pick a quality level, so swap it for imagemin-mozjpeg. Add the import at the top of the file:

const imageminMozjpeg = require('imagemin-mozjpeg');

Then add a plugins array inside the object passed to ImageminPlugin():

new ImageminPlugin({
  pngquant: ({quality: [0.5, 0.5]}),
  plugins: [imageminMozjpeg({quality: 50})]
})

This tells webpack to compress JPEGs to quality 50 via Mozjpeg (0 is worst, 100 is best).

A note on configuration structure: settings for plugins that ship as defaults with imagemin-webpack-plugin—like Pngquant—go directly as key-object pairs in the options. Non-default plugins, like Mozjpeg, must be listed in the plugins array instead. Your full config should now look like:

const imageminMozjpeg = require('imagemin-mozjpeg');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');

module.exports = {
  entry: './index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new CopyWebpackPlugin([{
      from: 'img/**/**',
      to: path.resolve(__dirname, 'dist')
    }]),
    new ImageminPlugin({
      pngquant: ({quality: [0.5, 0.5]}),
      plugins: [imageminMozjpeg({quality: 50})]
    })
  ]
}

Verify the result

Re-run webpack:

webpack --config webpack.config.js --mode production

PNG and JPEG warnings should be gone. But build-time checks only catch images that exceed size limits—they won't tell you if something is merely under-compressed. That's where Lighthouse helps.

Open the live version of your site, then run the Lighthouse performance audit from the options menu and check that the Efficiently encode images audit passes.

Passing 'Efficiently encode images' audit in Lighthouse

That pass confirms your images are now compressed to an appropriate level.