Noob Front End Engineer Blog

CONTACT

npm-scriptsで画像圧縮を自動化する

2021/02/03

概要

npm-scriptsを用いて、画像の追加・変更を監視し
自動で圧縮してくれるモジュールを作成する方法を紹介します!

完成品はこちらです。
使用方法はREADME.mdに記載してありますので、お急ぎの方は上記を使用してみてください。

Github強化中なので、☆, フォローいただけると喜びます

nodelinuxコマンドに対する基礎的な知識はあるものとして解説を進めていきます。

環境構築

今回使用するnode_module達は下記の通りです。

module description
imagemin 画像圧縮してくれる
imagemin-keep-folder ディレクトリ構造を維持したまま圧縮してくれる
imagemin-gifsicle gif の圧縮をしてくれる
imagemin-mozjpeg jpeg の圧縮をしてくれる
imagemin-pngquant png の圧縮をしてくれる
imagemin-svgo scg の圧縮をしてくれる
onchange 変更の監視をしてくれる

まずは、今回のデモを行う為のディレクトリを作成・移動、
必要なモジュールをインストールしていきましょう。

initの際にでてくる入力項目は任意で問題ありません。

bash
# ディレクトリ作成
mkdir demo

# ディレクトリ移動
cd demo

# npm 初期設定
npm init

# モジュールインストール
npm install imagemin imagemin-keep-folder imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo onchange -D

今回のデモは下記のようなディレクトリ構造で行っていきます。

demo
  └ dist
     └ img   # <-- 圧縮後の画像の出力先
  └ src
     └ img   # <-- 圧縮前の画像の格納場所

コマンドでもエクスプローラーでも構わないので、
dist/img/ディレクトリとsrc/img/ディレクトリを作成しておいてください。

package.jsonの編集

先ほどのモジュールインストールの際に行った
npm initによってpackage.jsonが作成されていると思うので
そちらの編集を行っていきましょう。

package.json"script"の箇所に下記を追加してください。

package.json
"press": "onchange src/img/**/*.{jpg,png,gif,svg} -- node imagemin.js {{changed}}"

やっている事としては、先ほどインストールを行ったonchangeモジュールが
src/img/**/*.{jpg,png,gif,svg}を監視し、変更が検知されたら
node imagemin.js {{changed}}を実行してくれるという処理です。
このimagemin.jsについては、次のセクションで作成を行っていきます。

node.js ではnode 〇〇.jsで指定したjsファイルを実行してくれます。
更にコマンドラインから引数を渡す事も可能なので、今回はonchangeモジュールが
検知した変更ファイルを教えてくれる{{changed}}を引数として渡しています。

imageminの設定ファイル作成

package.jsonと同じ階層に、設定用のJSファイルを作成してください。
このファイル名は特に指定はありませんが、今回は先ほどpackage.json
指定したimagemin.jsで作成していきます。

imagemin.js
const imagemin = require("imagemin-keep-folder")
const imageminMozjpeg = require("imagemin-mozjpeg")
const imageminPngquant = require("imagemin-pngquant")
const imageminGifsicle = require("imagemin-gifsicle")
const imageminSvgo = require("imagemin-svgo")

imagemin([process.argv[2]], {
  plugins: [
    imageminMozjpeg({ quality: 80 }),
    imageminPngquant(),
    imageminGifsicle(),
    imageminSvgo(),
  ],
  replaceOutputDir: output => {
    return output.replace(/img\//, "../dist/img/")
  },
}).then(() => {
  console.log("Images optimized")
})

設定ファイルの上部は使用するimagemin系列のモジュールを読み込んでいます。
今回はディレクトリ構造を維持したまま書き出しを行ってほしいのでimagemin-keep-folderの方を使用しています。

imagemin.js
imagemin([process.argv[2]], {

上記で使用しているprocess.argv[2]という箇所には、
先ほどpackage.jsonで渡した引数{{changed}}の値が入ってきています。
コマンドラインからの引数を参照する場合、指定方法が少し特殊でこのような書き方になってます。

こちらについては、他の方が詳しく書いてくださっているので
こちらの素敵記事を参考にしてください。 https://qiita.com/furusin_oriver/items/f030d1eaa9e7b54233c3

pluginsでは、使用するプラグインを指定しています。
それぞれの圧縮率等のオプションを設定する事ができるので、こちらについてはお好みでどうぞ

replaceOutputDirでは出力先の指定をしています。

imagemin.js
output.replace(/img\//, "../dist/img/")

上記の様にありますが、outputには圧縮する画像の path が入っています。
今回で言うと{{changed}}の値が入っており、/src/img/test/test.pngという画像を
追加したとすると、このoutputにも同じ値がはいります。その値にreplaceを行うと
/src../dist/img/test/test.pngとなり、今回想定しているディレクトリに出力されるようになります。

実行

下記を実行し、/src/img/ディレクトリに適当な画像を保存してみると圧縮が行われるはずです!

bash
npm run press

おわりに

npm-scriptsで画像圧縮を自動化する手法を調べると幾つか記事は見つかったのですが
画像を圧縮したいタイミングでコマンドを打つ手法が一番多く、監視を行って圧縮する手法を書いたものは
ありませんでした。

幾つかの記事を参考に、この手法を作成する事は出来ましたが
画像圧縮くらいであれば、自動化しなくとも都度コマンドを打っても問題ないよな…
と思って、完成例には監視で圧縮する場合と、コマンドで圧縮する場合の2つ用意しました🙆‍♂️

参考にさせていただいた記事

https://techblog.lclco.com/entry/2018/08/31/180000
https://qiita.com/k-gen/items/79812b04593b233b1ac1


Written by daichi iwamoto