Convert JPEG and PNG to WebP at Build Time With webpack
Use image-webpack-loader and imagemin-webp to automatically convert images to WebP during the webpack build process, keeping source files as JPEG or PNG.
webpack can automatically convert your images to WebP at build time using image-webpack-loader with the webp option, or the imagemin-webp plugin — keeping your source images as JPEG or PNG and outputting optimised WebP assets without any manual conversion step. This lets your development workflow stay unchanged while production builds ship the most efficient format available.
Installing Dependencies #
# npm
npm install --save-dev image-webpack-loader
# yarn
yarn add -D image-webpack-loader
# pnpm
pnpm add -D image-webpack-loader
image-webpack-loader wraps imagemin and its plugin suite, including imagemin-webp, which does the actual WebP encoding. You don’t need to install imagemin separately — it comes as a transitive dependency.
Configuring webpack to Output WebP #
Add image-webpack-loader as a second loader after file-loader (or asset/resource in webpack 5) in your module rules. Loaders run right to left, so image-webpack-loader processes the image first, then file-loader emits the result to the output directory.
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/',
},
},
{
loader: 'image-webpack-loader',
options: {
webp: {
quality: 80,
lossless: false,
},
},
},
],
},
],
},
};
With this configuration, image-webpack-loader converts all matched images to WebP and passes the WebP bytes to file-loader. The emitted file retains its original extension (.jpg, .png) but contains WebP data. Pair this with the <picture> element or content negotiation so browsers that don’t support WebP never receive the file.
Generating Separate .webp Files Alongside Originals #
For the most reliable cross-browser setup, keep the original JPEG or PNG file intact and emit a parallel .webp file. Use webp-webpack-plugin to add this as a separate build step.
Install the Plugin #
npm install --save-dev webp-webpack-plugin
Configure the Plugin #
const WebpWebpackPlugin = require('webp-webpack-plugin');
module.exports = {
plugins: [
new WebpWebpackPlugin({
config: [
{
test: /\.(jpe?g|png)$/i,
options: {
quality: 80,
},
},
],
strict: true,
}),
],
};
With strict: true, the build fails if any image cannot be converted, helping you catch problems early. The plugin walks the webpack output assets after compilation and creates a .webp sibling for each matched image — so hero.jpg becomes both hero.jpg and hero.webp in your dist folder.
After running your first build with WebP output, check the dist/images/ directory and compare file sizes between the originals and their .webp counterparts. A well-configured WebP conversion should reduce JPEG sizes by 25–35% and PNG sizes by 60–80%. If savings are lower than expected, try adjusting the quality option.
webpack 5 Asset Modules #
webpack 5 replaces file-loader with built-in Asset Modules. Update your configuration accordingly.
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name][ext]',
},
use: [
{
loader: 'image-webpack-loader',
options: {
webp: {
quality: 80,
},
},
},
],
},
],
},
};
Vite Alternative #
If you use Vite instead of webpack, vite-imagetools provides a similar build-time conversion pipeline with a clean query-parameter API.
Install #
npm install --save-dev vite-imagetools
Configure #
import { imagetools } from 'vite-imagetools';
export default {
plugins: [imagetools()],
};
Import With Format Transform #
import heroUrl from './hero.jpg?format=webp&quality=80';
export default function Hero() {
return <img src={heroUrl} alt="Hero" />;
}
The ?format=webp&quality=80 query string tells vite-imagetools to convert the image at build time and return the URL of the generated WebP asset. You can chain multiple transforms in a single import.
Common Build-Time Conversion Options #
- quality — number, default
75. Lossy encoding quality (1–100). Values of 75–85 are a good balance of size and fidelity. - lossless — boolean, default
false. Enable lossless encoding. File sizes are larger but pixel-perfect. - nearLossless — number, no default. Near-lossless quality (0–100). A quality of 0 is identical to lossless.
- method — number, default
4. Encoding speed/quality trade-off (0–6). Higher values produce smaller files but are slower.
