完全に自己満足かもしれませんが、以下の理由で画像の最適化に取り組みました。

  • Google PageSpeed Insightsで毎回画像サイズが最適化されていないと毎回怒られる
  • 画像ファイルのサイズが無駄に大きいため、iPhoneからアクセスした時に余計なパケットを消費するのが悔しい

画像の最適化を全て手動でやると挫折してしまうので、タスクランナーであるgulpで自動化を行いました。

やりたいこと

  1. Markdown形式のファイルに対して画像ファイルをドラッグ&ドロップで画像リンク生成
  2. 画像ファイルをレスポンス対応(srcsets)させるため、数種類のサイズにリサイズ
  3. リサイズ後の画像ファイルを最適化(圧縮)

「1.」のドラッグ&ドロップで画像リンク生成は、エディタのプラグインで実現することにし、「2.」「3.」をgulpのタスクで実現を目指しました。

画像のresponsive対応

なんとなく、320px,640px,1280px,オリジナルファイルという4種類にリサイズするようにしてみました。

gulp.task('responsive', function(){
  return gulp.src(['src/images/**/*.jpg','src/images/**/*.png'], { base: 'src'})
        .pipe(responsive({
          // Resize all JPG images to three different sizes: 200, 500, and 630 pixels
          'images/**/*.jpg': [{
            width: 320,
            rename: { suffix: '-320x' },
          }, {
            width: 640,
            rename: { suffix: '-640x' },
          }, {
            width: 1280,
            rename: { suffix: '-1280x' },
          }, {
            // Compress, strip metadata, and rename original image
            rename: { suffix: '-o' },
          }],
          // Resize all PNG images to be retina ready
          'images/**/*.png': [{
            width: 250,
          }, {
            width: 250 * 2,
            rename: { suffix: '@2x' },
          }],
        }, {
          // Global configuration for all images
          // The output quality for JPEG, WebP and TIFF output formats
          quality: 70,
          // Use progressive (interlace) scan for JPEG and PNG output
          progressive: true,
          // Strip all metadata
          withMetadata: false,
      }))
      .pipe(gulp.dest('static/'));
});

gulp-responsive/multiple-resolutions.md at master · mahnunchik/gulp-responsive

Tips 出力処理

gulp.srcbaseというオプションがあり、これを指定するとディレクトリ構造を維持して出力することができます。

var gulp = require('gulp');

gulp.task('copy', function() {
    return gulp.src(
        ['src/images/**/.jpg', 'src/images/**/.png'],
        { base: 'src' }
    )
    .pipe(gulp.dest('static/'));
} );

画像の最適化

画像の最適化には、gulp-imageminを利用しました。

var imagemin = require('gulp-imagemin');
gulp.task('imagemin', function() {
  return gulp.src('src/images/**/*.jpg')
      .pipe(imagemin())
      .pipe(gulp.dest('static/'));
});

組み合わせた結果

Hugoのルートディレクトリでgulpを叩けば、jpg, pngを監視し、ファイルが追加されれば、画像フォルダに変換後の画像が作成されるようになります。

gulp.task('default', function(cb) {
  var watcher = gulp.watch('src/images/**/*.{jpg,png}');
  watcher.on('change', function(event) {
    console.log(event);
    console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
    const extname = event.path.split(".").pop(); // TODO error handle
    console.log(extname);
    if (extname === "jpg") {
      gulp.src(event.path, { base: 'src'})
          .pipe(responsive({
            // Resize all JPG images to three different sizes: 200, 500, and 630 pixels
            'images/**/*.jpg': [{
              width: 640,
            }, {
              width: 64,
              rename: { suffix: '-64x'},
            }, {
              width: 320,
              rename: { suffix: '-320x' },
            }, {
              width: 640,
              rename: { suffix: '-640x' },
            }, {
              width: 1280,
              rename: { suffix: '-1280x' },
            }, {
              // Compress, strip metadata, and rename original image
              rename: { suffix: '-o' },
            }],
          }))
        .pipe(imagemin())
        .pipe(gulp.dest('static/'));
    } else if (extname === "png") {
      gulp.src(event.path, { base: 'src'})
          .pipe(responsive({
            // Resize all PNG images to be retina ready TODO
            'images/**/*.png': [{
              width: 64,
              rename: { suffix: '-64x'}
            }, {
              width: 640,
            }, {
              width: 640 * 2,
              rename: { suffix: '@2x' },
            }],
          }, {
            // Global configuration for all images
            // The output quality for JPEG, WebP and TIFF output formats
            quality: 70,
            // Use progressive (interlace) scan for JPEG and PNG output
            progressive: true,
            // Strip all metadata
            withMetadata: false,
        }))
        .pipe(imagemin())
        .pipe(gulp.dest('static/'));
    } else {
      console.log("not jpg or png");
    }

  });

  // hugo
  exec('hugo server -t hugo-zen', function(err, stdout, stderr) {
    console.log(stdout);
    console.log(stderr);
    if (err) return cb(err); // return error
    cb(); // finished task
  });
});

まとめ

画像の最適化は、手動だとめんどくさくてなかなか出来ないが、一度自動化してしまえば後は楽です。 少しずつメンテナンスを加えて使い勝手を良くしていきたいと思います。

参考