Reputation: 711
I want to generate webp files from jpg/png from webpack. To do that i using image-webpack-plugin (https://github.com/tcoopman/image-webpack-loader)
In the plugin documentation it's written that the webp additional optimizer "Compress JPG & PNG images into WEBP" (https://github.com/tcoopman/image-webpack-loader#usage) but after followed the documentation steps the conversion not work.
The files are exported in jpg but nothing is converted.
I've already followed these posts but i've don't understand how to translate in a "non-react" environment :
Webpack imagemin plugin to compress jpg, png and create webp?
Webpack (Encore): convert images to webp using image-webpack-loader
webpack.config.js
{
test:/\.(gif|png|jpe?g|svg)$/i,
use:[
{
loader:'file-loader',
options:{
outputPath:'images',
name:'[name].[ext]'
}
},
{
loader:'image-webpack-loader',
options:{
mozjpeg:{
progressive:true,
quality:65
},
optipng:{ enabled: false },
pngquant:{ quality: [ 0.65, 0.90 ], speed:4 },
gifsicle:{ interlaced: false },
webp:{ quality: 75 }
}
}
]
}
Is there a reliable and clean way to turn jpg / png files into webp via webpack ?
Upvotes: 8
Views: 18725
Reputation: 154
How to create a webp image in the same path as in the working directory.
create-webp.mjs
:import imagemin from 'imagemin';
import imageminWebp from 'imagemin-webp';
import { promises as fsPromises } from 'node:fs';
import { promisify } from 'node:util';
import path from 'node:path';
import fs from 'graceful-fs';
const writeFile = promisify(fs.writeFile);
imagemin(['./src/img/**/*.{jpg,jpeg,png}'], {
plugins: [
imageminWebp({ quality: 100 }),
],
}).then(files => files
.forEach(async v => {
let source = path.parse(v.sourcePath);
v.destinationPath = `${source.dir}/${source.name}.webp`;
await fsPromises.mkdir(path.dirname(v.destinationPath), { recursive: true });
await writeFile(v.destinationPath, v.data);
})
);
node ./create-webp.mjs
before run webpack.webpack.config
:{
test: /\.(gif|png|jpe?g|svg|webp)$/i,
type: 'asset/resource',
generator: {
filename: content => {
return content.filename.replace('src/', '');
},
},
},
Upvotes: 0
Reputation: 711
Finally, i've found a proper solution. For future people who will come here :
I no longer use image-webpack-loader but imagemin
& imagemin-webp
Verify you have imagemin
& imagemin-webp
installed before do anything.
Create a webpack.config.prod.js
file to create a specific image conversion script before the webpack build script.
Into the array ['src/images/*.{jpg,png}']
is the input, 'destination' the output. The output is via src
to avoid to load unused stuff in the dist
directory and it permit to a potential ejs plugin to require directly .webp files by a 'require' command.
const imagemin = require( "imagemin" )
const webp = require( "imagemin-webp" )
imagemin( ['src/images/*.{jpg,png}'], {
destination: 'src/images',
plugins: [
webp( { quality: 60 } )
]
} )
package.json
dedicated to the production"scripts": {
"preprod": "node webpack.config.prod.js",
"prod": "npm webpack"
}
Upvotes: 19
Reputation: 500
You can use responsive loader. Steps for using from official doc:
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpe?g|png|webp)$/i,
use: {
loader: "responsive-loader",
options: {
// If you want to enable sharp support:
adapter: require("responsive-loader/sharp"),
},
},
},
],
},
}
import responsiveImage from 'img/myImage.jpg?sizes[]=300,sizes[]=600,sizes[]=1024,sizes[]=2048';
import responsiveImageWebp from 'img/myImage.jpg?sizes[]=300,sizes[]=600,sizes[]=1024,sizes[]=2048&format=webp';
// Outputs
// responsiveImage.srcSet => '2fefae46cb857bc750fa5e5eed4a0cde-300.jpg 300w,2fefae46cb857bc750fa5e5eed4a0cde-600.jpg 600w,2fefae46cb857bc750fa5e5eed4a0cde-600.jpg 600w ...'
// responsiveImage.images => [{height: 150, path: '2fefae46cb857bc750fa5e5eed4a0cde-300.jpg', width: 300}, {height: 300, path: '2fefae46cb857bc750fa5e5eed4a0cde-600.jpg', width: 600} ...]
// responsiveImage.src => '2fefae46cb857bc750fa5e5eed4a0cde-300.jpg'
// responsiveImage.toString() => '2fefae46cb857bc750fa5e5eed4a0cde-300.jpg'
...
<picture>
<source srcSet={responsiveImageWebp.srcSet} type='image/webp' />
<img
src={responsiveImage.src}
srcSet={responsiveImage.srcSet}
width={responsiveImage.width}
height={responsiveImage.height}
sizes='(min-width: 1024px) 1024px, 100vw'
loading="lazy"
/>
</picture>
...
Upvotes: 0
Reputation: 21
Try this. https://github.com/GaoYYYang/image-optimize-loader#3-transform-your-pngjpg-into-webp
When you enable compress.webp, it will transform your png/jpg into webp files, and there will be no png/jpg files generated. Your source code will directly use webp file instead of png/jpg.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|webp|git|svg|)$/i,
use: [
{
loader: `img-optimize-loader`,
options: {
compress: {
// This will transform your png/jpg into webp.
webp: true,
disableOnDevelopment: true
}
},
},
],
},
],
},
};
Upvotes: 2