iTranslated by AI
Optimize Images with npm scripts (Including WebP Conversion and File Watching)
Requirements
- Target and optimize images in the
srcdirectory - Output optimized images to the
htdocsdirectory without changing the structure - Support converting jpg and png to WebP
- Allow outputting jpg and png simultaneously for projects requiring WebP fallbacks
- Do not use WebP
- Use WebP, but fallback images are required
- Fallback images are unnecessary; use WebP
Install packages
Install the necessary packages for image optimization.
npm i -D imagemin-keep-folder imagemin-mozjpeg imagemin-pngquant imagemin-gifsicle imagemin-svgo imagemin-webp
There is an Issue where imagemin ignores the directory structure (it doesn't look like it's been merged yet?).
In this case, I'm using "imagemin-keep-folder" to resolve this.
Also install npm-run-all, which allows for concise descriptions and cross-platform support, and onchange, which provides file watching capabilities.
npm i -D npm-run-all onchange
Create the image optimization execution file
Create scripts/imagemin.mjs as follows.
Adjust the quality setting to match your project.
import imagemin from 'imagemin-keep-folder';
import imageminMozjpeg from 'imagemin-mozjpeg';
import imageminPngquant from 'imagemin-pngquant';
import imageminGifsicle from 'imagemin-gifsicle';
import imageminSvgo from 'imagemin-svgo';
import imageminWebp from 'imagemin-webp';
/**
* Specify the mode for WebP usage and fallback.
* - 'noWebp': Do not use WebP; output only original images.
* - 'useIfPossible': Use WebP; output original images only if they cannot be converted to WebP.
* - 'fallback': Use WebP; also output original images.
*/
optimizeImages('useIfPossible');
/**
* Optimizes images that can be converted to WebP.
*/
async function optimizeWebpConvertibleImages() {
await imagemin(['src/**/*.{jpg,jpeg,png}'], {
use: [
imageminMozjpeg({ quality: 85, progressive: true }),
imageminPngquant({ quality: [0.85, 0.9] }),
],
replaceOutputDir: output => output.replace(/src\//, 'htdocs/')
});
}
/**
* Optimizes images that cannot be converted to WebP.
*/
async function optimizeNonWebpImages() {
await imagemin(['src/**/*.{gif,svg}', '!src/assets/svg/*.svg'], {
use: [
imageminSvgo(),
imageminGifsicle(),
],
replaceOutputDir: output => output.replace(/src\//, 'htdocs/')
});
}
/**
* Generates WebP images.
*/
async function generateWebpImages() {
await imagemin(['src/**/*.{jpg,jpeg,png}'], {
use: [
imageminWebp({ quality: 70 }),
],
replaceOutputDir: output => output.replace(/src\//, 'htdocs/')
});
}
/**
* Optimizes images.
* @param {string} webpMode - WebP output mode ('noWebp', 'useIfPossible', 'fallback')
*/
async function optimizeImages(webpMode) {
switch (webpMode) {
case 'noWebp':
await optimizeWebpConvertibleImages();
await optimizeNonWebpImages();
break;
case 'useIfPossible':
await generateWebpImages();
await optimizeNonWebpImages();
break;
case 'fallback':
await optimizeWebpConvertibleImages();
await generateWebpImages();
await optimizeNonWebpImages();
break;
default:
throw new Error('Invalid webpMode');
}
}
Passing an arbitrary string as an argument to optimizeImages() allows you to switch the output format.
-
noWebp: Do not use WebP; only original images are output. -
useIfPossible: Use WebP; original images are output only if they cannot be converted to WebP. -
fallback: Use WebP; original images are also output.
If you are in an environment where you can ignore IE, useIfPossible is sufficient.
Jpg and png are converted to WebP, and since svg and gif cannot be converted, they are optimized and output as-is.
Set up npm scripts
I haven't included scripts for HTML or CSS here, but I have extracted the parts related to image processing.
"scripts": {
"start": "run-s -c dev watch",
"build": "npm-run-all -s clean -p build:*",
"watch": "run-p watch:*",
"watch:image": "onchange \"src/**/*.{jpg,jpeg,png,gif,svg}\" -- npm run dev:image",
"dev": "run-p dev:*",
"dev:image": "NODE_ENV=development run-s -c image:*",
"build:image": "NODE_ENV=production run-s -c image:*",
"image:min": "node scripts/imagemin.mjs",
"clean": "run-p clean:*",
"clean:htdocs": "shx rm -rf \"htdocs\" && shx echo \"Done cleaning\""
},
-
image:minexecutes the image optimization. -
devis for development builds, whilebuildis for production builds. -
run-sruns tasks sequentially, and the-coption ensures that processing continues to the end even if an error occurs. - You can use glob patterns like
run-p dev:*ornpm-run-all -s clean -p build:*to execute tasks along with others (cleanis a script that deletes the htdocs directory). -
onchange \"src/**/*.{jpg,jpeg,png,gif,svg}\" -- npm run dev:imagemonitors image files. - By using
run-s -c dev watch, the development builds are executed in sequence, and the process enters a watching state upon completion. -
shx (requires installation) is used to delete the
htdocsdirectory.
Discussion
webpや画像最適化の自動化で悩んでいたところ、こちらの記事を見つけてとても嬉しかったです!
一点だけご質問させていただきます。
srcの画像削除してもhtdocsの画像は削除されなくて"build": "npm-run-all -s clean -p build:*",を実行してみたら
ERROR: Task not found: "clean"と表示されました。
cleanタスクは何を設定したらいいでしょうか?
お忙しいところ恐縮ですが、何卒よろしくお願いいたします。
お役に立ててよかったです!
cleanに関してnpm scriptsを設定するに追記しました。
shxというライブラリでディレクトリを削除していますが、別のライブラリでも問題ありません。
ご回答いただきありがとうございます!
とても勉強になりました!