Web制作のための画像圧縮とWebP生成
4 月が終わり、GW に突入しますね。
季節の変わり目になりクーラーのタイミングを伺ってる、スピッカートの金山( )です。
今回は、弊社で使用している Web 制作のための画像圧縮と WebP 生成を紹介します!
毎回 Web サービスなどを用いて圧縮すると効率が悪いので、弊社では自動化しています。
圧縮と WebP 生成には、 sharp というライブラリを使用しています。
sharp-cli があり webpack 上で簡単に使用できるのですが、ここ一年以上更新がされていないので今回は使用しません。
かわりに、npm script で実行します。
結論(コード)
最初に結論を書くのがいいと聞くので、最初にコード全体を書きます。
"sharp:watch": "onchange \"src/assets/images/**/*.{png,jpg,jpeg,svg,gif}\" -- node sharp-watch.js {{changed}}",
const fs = require("fs");
const path = require("path");
const sharp = require("sharp");
let dirName = path.dirname(process.argv[2]);
let fileName = path.basename(process.argv[2]);
let outPutDir = `dist${dirName.replace("src", "")}`;
// 拡張子を取得
function getExtension(file) {
let ext = path.extname(file || "").split(".");
return ext[ext.length - 1];
}
const fileFormat = getExtension(fileName);
(() => {
// もしディレクトリがなければ作成
if (!fs.existsSync("dist/assets/images")) {
fs.mkdirSync("dist/assets/images");
}
// サブディレクトリがなければ作成
if (!fs.existsSync(outPutDir)) {
fs.mkdirSync(outPutDir);
}
let sh = sharp(`${dirName}/${fileName}`);
let webp = sharp(`${dirName}/${fileName}`);
if (fileFormat === "jpg" || fileFormat === "jpeg") {
sh = sh.jpeg({ quality: 70 });
webp = webp.webp({ quality: 70 });
} else if (fileFormat === "png") {
sh = sh.png({ quality: 70 });
webp = webp.webp({ quality: 70 });
} else if (fileFormat === "gif") {
sh = sh.gif({ quality: 70 });
webp = webp.webp({ quality: 70 });
} else if (fileFormat === "svg") {
// svgは複製のみ
fs.copyFile(process.argv[2], `${outPutDir}/${fileName}`, (err) => {
if (err) {
fs.unlinkSync(`${outPutDir}/${fileName}`);
console.log(`${fileName}を${outPutDir}から削除しました。`);
return;
}
console.log(`${fileName}を${outPutDir}に複製しました。`);
});
return;
} else {
console.log("対応していないファイル形式です。");
return;
}
sh.toFile(`${outPutDir}/${fileName}`, (err, info) => {
if (err) {
// 該当ファイルがない場合はdistから削除
if (fs.existsSync(`${outPutDir}/${fileName}`)) {
fs.unlinkSync(`${outPutDir}/${fileName}`);
fs.unlinkSync(`${outPutDir}/webp/${fileName.replace(/\.[^/.]+$/, ".webp")}`);
console.log(`${fileName}を${outPutDir}から削除しました。`);
}
return;
}
console.log(`${fileName}を圧縮しました。 ${info.size / 1000}KB`);
// webp生成、もしディレクトリがなければ作成
if (!fs.existsSync(`${outPutDir}/webp`)) {
fs.mkdirSync(`${outPutDir}/webp`);
}
webp.toFile(`${outPutDir}/webp/${fileName.replace(/\.[^/.]+$/, ".webp")}`, (err, info) => {
console.log(`${fileName}をwebpに変換しました。 ${info.size / 1000}KB`);
});
});
})();
解説
それでは、簡単な解説をしていきます!
まずは、必要なパッケージをインストールします。
npm install -D sharp onchange
onchange は、ファイルの変更を監視するためのパッケージです。
"sharp:watch": "onchange \"src/assets/images/**/*.{png,jpg,jpeg,svg,gif}\" -- node sharp-watch.js {{changed}}",
{{ changed }} に変更したファイルのパスが渡されます。
jpeg,jpg,png,gif は圧縮と webp 生成を行い、svg は dist へ複製のみを実施します!
const fs = require("fs");
const path = require("path");
const sharp = require("sharp");
まず、Node.js の path、fs、モジュール をインストールします。
詳しくは下記をご覧ください。
今回は、パスの読み込みとファイルの生成で使用しています。
let dirName = path.dirname(process.argv[2]);
let fileName = path.basename(process.argv[2]);
let outPutDir = `dist${dirName.replace("src", "")}`;
// 拡張子を取得
function getExtension(file) {
let ext = path.extname(file || "").split(".");
return ext[ext.length - 1];
}
const fileFormat = getExtension(fileName);
ここでは、ディレクトリ名、ファイル名、アウトプット先、拡張子を取得しています。
process.argv[2] は、コマンドライン引数で渡されたファイルのパスです。
"node sharp-watch.js {{changed}}",
上記だと、node が process.argv[0] , sharp-watch.js が process.argv[1] , {{changed}} が process.argv[2] となっています。
// もしディレクトリがなければ作成
if (!fs.existsSync("dist/assets/images")) {
fs.mkdirSync("dist/assets/images");
}
// サブディレクトリがなければ作成
if (!fs.existsSync(outPutDir)) {
fs.mkdirSync(outPutDir);
}
let sh = sharp(`${dirName}/${fileName}`);
let webp = sharp(`${dirName}/${fileName}`);
ディレクトリが無ければ作成します。
さらに sharp をインスタンス化します。
if (fileFormat === "jpg" || fileFormat === "jpeg") {
sh = sh.jpeg({ quality: 70 });
webp = webp.webp({ quality: 70 });
} else if (fileFormat === "png") {
sh = sh.png({ quality: 70 });
webp = webp.webp({ quality: 70 });
} else if (fileFormat === "gif") {
sh = sh.gif({ quality: 70 });
webp = webp.webp({ quality: 70 });
} else if (fileFormat === "svg") {
// svgは複製のみ
fs.copyFile(process.argv[2], `${outPutDir}/${fileName}`, (err) => {
if (err) {
fs.unlinkSync(`${outPutDir}/${fileName}`);
console.log(`${fileName}を${outPutDir}から削除しました。`);
return;
}
console.log(`${fileName}を${outPutDir}に複製しました。`);
});
return;
} else {
console.log("対応していないファイル形式です。");
return;
}
if 文で拡張子毎に処理を分岐します。
quality で画質調整(圧縮率)を個別にすることができます。
svg は複製のみを実施しています。
sh.toFile(`${outPutDir}/${fileName}`, (err, info) => {
if (err) {
// 該当ファイルがない場合はdistから削除
if (fs.existsSync(`${outPutDir}/${fileName}`)) {
fs.unlinkSync(`${outPutDir}/${fileName}`);
fs.unlinkSync(`${outPutDir}/webp/${fileName.replace(/\.[^/.]+$/, ".webp")}`);
console.log(`${fileName}を${outPutDir}から削除しました。`);
}
return;
}
console.log(`${fileName}を圧縮しました。 ${info.size / 1000}KB`);
// webp生成、もしディレクトリがなければ作成
if (!fs.existsSync(`${outPutDir}/webp`)) {
fs.mkdirSync(`${outPutDir}/webp`);
}
webp.toFile(`${outPutDir}/webp/${fileName.replace(/\.[^/.]+$/, ".webp")}`, (err, info) => {
console.log(`${fileName}をwebpに変換しました。 ${info.size / 1000}KB`);
});
});
ここで圧縮と WebP 生成を行います。
さらに、画像を削除した場合は dist からも削除します。
まとめ
Web サイトにおけるスピードアップについて、最近より関心が高くなっていると思います。
そこで画像の圧縮や新しい拡張子(WebP,AVIF など)を使用して、Web サイトのスピードアップを実現することができます。
Webpack を使用して、imagemin-webpack-plugin 等パッケージで圧縮することも可能ですが、ビルド時間が膨大になることが多く sharp を用いて開発体験を向上させることができました。
詳しく比較ができればいいのですが、面倒なので今回は割愛します!
是非、ご自身の手で試してみてください(笑)!
参考
Author And Source
この問題について(Web制作のための画像圧縮とWebP生成), 我々は、より多くの情報をここで見つけました https://zenn.dev/spicato_inc/articles/6afdf43d0f0a97著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol