gulpで画像を圧縮する

更新

タグ:

結論

ソースコード

動作確認環境

Node.js v16.13.0

"devDependencies": {
  "del": "^6.0.0",
  "gulp": "^4.0.2",
  "gulp-imagemin": "^7.1.0",
  "gulp-notify": "^4.0.0",
  "gulp-plumber": "^1.2.1",
  "imagemin-mozjpeg": "^9.0.0",
  "imagemin-pngquant": "^9.0.2"
}

使い方

  1. プロジェクトのディレクトリに移動し、npm iコマンドでパッケージをインストールする
  2. npx gulp imageminコマンドでsrc/img/以下の画像を圧縮してdist/assets/img/以下に吐き出す
  3. npx gulp watchコマンドでwatchモードを起動できる。watchモード下ではsrc/img/以下の変更を検知して自動で画像圧縮タスクが走る

解説

gulpfile.jsは以下のように記述しています。

const gulp = require("gulp");
const plumber = require("gulp-plumber");
const notify = require("gulp-notify");
const imagemin = require("gulp-imagemin");
const imageminMozjpeg = require("imagemin-mozjpeg");
const pngquant = require("imagemin-pngquant");
const del = require("del");

const imageMinify = () => {
  return gulp
    .src("src/img/**/*", { since: gulp.lastRun(imageMinify) })
    .pipe(plumber({ errorHandler: notify.onError("<%= error.message %>") }))
    .pipe(
      imagemin([
        imagemin.gifsicle({ optimizationLevel: 3 }),
        pngquant({ quality: [0.65, 0.8], speed: 1 }),
        imageminMozjpeg({
          quality: 65,
        }),
        imagemin.svgo({
          plugins: [
            {
              removeViewBox: false,
            },
          ],
        }),
      ]),
    )
    .pipe(gulp.dest("dist/assets/img/"));
};

const cleanImage = () => {
  return del("dist/assets/img/");
};

const watch = (done) => {
  gulp.watch("src/img/**/*", imageMinify);
  done();
};

exports.watch = watch;
exports.imagemin = gulp.series(cleanImage, imageMinify);

画像圧縮タスクはimageMinifyという名前の関数で定義しています。

const imageMinify = () => {
  ...
};

画像圧縮のためのパッケージとしてimageminを使用しています。gulp用のパッケージgulp-imageminがあるので、今回はこちらを使用します。また、JPEGのコンバーターをしてMozJPEGを、PNGのコンバーターとしてpngquantを使用しています。共にimageminのプラグインimagemin-mozjpegおよびimagemin-pngquantが提供されているので、それらを使用します。

gulpはgulpの本体、gulp-plumberはエラーが起きたときにgulpタスクを停止させないようにするパッケージ、gulp-notifyはエラーを通知するためのパッケージです。

delはディレクトリ・ファイルを削除するためのパッケージです(後述)。

const gulp = require("gulp");
const plumber = require("gulp-plumber");
const notify = require("gulp-notify");
const imagemin = require("gulp-imagemin");
const imageminMozjpeg = require("imagemin-mozjpeg");
const pngquant = require("imagemin-pngquant");
const del = require("del");
...

src/img/**/*ディレクトリのファイルをソースとして処理を行います。

optimizationLevelqualityといった項目を変更することで、圧縮のクオリティを調整できます。実際に圧縮してみて、加減してみるといいでしょう。

最後にdist/assets/img/へ画像を吐き出しています。

...
const imageMinify = () => {
  return gulp
    // `{ since: gulp.lastRun(imageMinify) }`を設定することで、
    // 前回実行時からの差分のファイルのみを対象としてタスクを実行することができる。
    .src("src/img/**/*", { since: gulp.lastRun(imageMinify) })
    .pipe(plumber({ errorHandler: notify.onError("<%= error.message %>") }))
    .pipe(
      imagemin([
        // GIF用の設定
        imagemin.gifsicle({ optimizationLevel: 3 }),
        // PNG用の設定
        pngquant({ quality: [0.65, 0.8], speed: 1 }),
        // JPEG用の設定
        imageminMozjpeg({
          quality: 65,
        }),
        // SVG用の設定
        imagemin.svgo({
          plugins: [
            {
              removeViewBox: false,
            },
          ],
        }),
      ])
    )
    .pipe(gulp.dest("dist/assets/img/"));
};
...

定義したimageMinify関数をimageminという名前でエクスポートしておきます。これによりnpx gulp imageminコマンドで画像圧縮タスクが走るようになりました。

...
exports.imagemin = imageMinify;
...

これで画像を圧縮できるようになりました。しかし、このままでは画像を追加する度に上記のコマンドを叩く必要があります。それでは面倒なので、src/img/ディレクトリに画像を追加、または画像を変更したら自動で画像圧縮のタスクが走るようにしてみます。

watchを使ってsrc/img/ディレクトリのファイルを監視対象とし、ファイルの追加・変更でimageMinifyが実行されるようにします。

こちらもwatchという名前でエクスポートしておきます。これによりnpx gulp watchコマンドでwatchモードを起動できます。普段の制作ではwatchモードを起動しておいた方が便利でしょう。

...
const watch = (done) => {
  gulp.watch("src/img/**/*", imageMinify);
  done();
};

exports.watch = watch;
...

最後に、もう1つやっておくことがあります。

現在の状態では、src/img/の画像を削除しても、dist/assets/img/の中の圧縮後のファイルは削除されません。もっと便利な方法があるかもしれませんが、ここではnpx gulp imageminで画像を圧縮する前に、dist/assets/img/ディレクトリを削除するという大雑把な方法を取ります。

新しくcleanImageという関数を定義します。この関数ではdelを使用してdist/assets/img/を削除する処理を行います。続いて、imageminの定義を更新します。gulp.series()を使用し、cleanImageimageMinifyの順で処理を実行するようにします。

npx gulp imageminコマンドで一旦圧縮済みの画像を全て削除したあと改めてimageMinifyを実行するようになりました。節目ごとにnpx gulp imageminを実行することで、srcdistでファイルの一貫性を保つことができます。

...
const imageMinify = () => {
  ...
};

const cleanImage = () => {
  return del("dist/assets/img/");
};

const watch = (done) => {
  gulp.watch("src/img/**/*", imageMinify);
  done();
};

exports.watch = watch;
exports.imagemin = gulp.series(cleanImage, imageMinify);

これで画像圧縮タスクの完成です。ディレクトリのパス等はお使いの環境に合わせて変更してください。