クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【gulp-imagemin】メタ言語コンパイル環境で画像圧縮も実行する

メタ言語の続きです。前回は外部のJSONファイルをTypeScriptで型付で読み込みました。今回はgulp-imageminなどをのパッケージを使って画像の圧縮設定もしてみます。それではいきましょう!

【目次】

※参考:前回記事
【TypeScript】外部のJSONファイルを型付で読み込む - クモのようにコツコツと

※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com

前回のおさらい

「unsei.ts」を「json」フォルダに移動し「unsei.json」にリネイム

https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201120/20201120060751.jpg

このunsee.jsonをTypeScriptで型を付けて読み込んでwebpackでバンドルした。

詳細は前回記事を参照

※参考:【TypeScript】外部のJSONファイルを型付で読み込む - クモのようにコツコツと

srcフォルダの中にも画像用のimgフォルダを作る

これまでメタ言語のコンパイルを主軸にしていたため、画像は手付かずだった。

コンパイル前のメタ言語ファイルを入れている「src」フォルダには画像ファイルは含めていなかった。

画像ファイルはコンパイル後の「dest」フォルダの中の「img」フォルダに直接アップしていた。 f:id:idr_zz:20201122094152j:plain

しかしできれば「dest」フォルダの中は触りたくない。自動的に作られるコンパイル結果のみをおきたい。

とはいえ単にsrcフォルダの中にimgフォルダを作ってそれをdestフォルダにコピーするだけなのも芸がないな。。

画像を圧縮する方法を調べる。

そういえば、画像って圧縮するとさらにスリムになってページで読み込み速度が上がるんだよな(Webデザイナー時代はフォトショの保存設定でサイズを下げたりしてたが)。

下記の記事の実例のように画像をgulpで圧縮すると見た目はほどんど変わらずにサイズが下がっている!

※参考:【デザイナー向け】gulpでかんたん画像圧縮 - Qiita

webpackでも画像圧縮できる(jsファイルにバンドルせずにフォルダ構成を保持もできる!)

※参考:webpackで画像を圧縮する方法 | HPcode

また、gulpやwebpackを使わなくてもpackage.jsonのnpm scriptsに設定を書くだけでも画像圧縮できる!

※参考:npm scriptsで画像圧縮を自動化した際の課題と検討事項 - LCL Engineers' Blog

いろいろな方法を調べたが共通するのはimageminというパッケージを使っていることだ。どうやら画像圧縮の定番らしい。


今回は「gulp-imagemin」を使って画像圧縮したい。下記の記事の方法がわかりやすかったのでこちらを参考に進める。

※参考:Gulpでいろんなフォーマットの画像を一括で圧縮する | オウンドメディア | 大阪市天王寺区SOHOホームページ制作 | デザインサプライ-DesignSupply.-

gulp-imageminをインストール

まず画像圧縮に必要な3つのパッケージをインストールする。

$ npm install --save-dev gulp-imagemin
$ npm install --save-dev imagemin-pngquant
$ npm install --save-dev imagemin-mozjpeg
  • gulp-imagemin:SVG(svgoプラグイン)とGIF(gifsicleプラグイン)の圧縮
  • imagemin-pngquant:PNG圧縮
  • imagemin-mozjpeg:JPG圧縮

SVGはsvgo、GIFはgifsicleというプラグインを使う。gulp-imagemin本体に含まれている。

PNGはimagemin-pngquant、JPGはimagemin-mozjpegはというプラグインを使う。これは本体と別でインストールする。

※参考:gulp-imagemin - npm

※参考:imagemin-pngquant - npm

※参考:imagemin-mozjpeg - npm

package.jsonを確認

"devDependencies": {
    "browser-sync": "^2.26.13",
    "gulp": "^4.0.2",
    "gulp-ejs": "^5.1.0",
    "gulp-imagemin": "^7.1.0",  // 追記
    "gulp-plumber": "^1.2.1",
    "gulp-rename": "^2.0.0",
    "gulp-replace": "^1.0.0",
    "gulp-sass": "^4.1.0",
    "gulp-typescript": "^6.0.0-alpha.1",
    "imagemin-mozjpeg": "^9.0.0", // 追記
    "imagemin-pngquant": "^9.0.1", // 追記
    "ts-loader": "^8.0.11",
    "webpack": "^5.4.0",
    "webpack-stream": "^6.1.1"
  },

3つのパッケージが追記されている!

gulpfile.jsでパッケージをインポート

gulpの設定ファイルgulpfile.jsでパッケージをインポートする。

const imagemin = require('gulp-imagemin');
const mozjpeg = require('imagemin-mozjpeg');
const pngquant = require('imagemin-pngquant');
  • 変数imagemingulp-imageminをインポート
  • 変数mozjpeg'imagemin-mozjpegをインポート
  • 変数pngquantimagemin-pngquantをインポート

画像圧縮設定

imageminという名前のgulp.tusk()で画像圧縮の設定をする

// 画像圧縮
gulp.task('imagemin', (done) => {
    gulp.src('./src/img/**/*.{jpg,jpeg,png,gif,svg}')
    .pipe(imagemin(
      [
        pngquant({ quality: '65-80', speed: 1 }),
        mozjpeg({ quality: 80 }),
        imagemin.svgo(),
        imagemin.gifsicle()
      ]
    ))
    .pipe(gulp.dest('./dest/img'));
    done();
});
  • gulp.task()を実行(第一引数はimagemin、第二引数は無名関数でその引数はdone
  • gulp.src()を実行(引数はパスで「/src/img」フォルダのファイル、拡張子はjpg,jpeg,png,gif,svgのいずれか
  • 一つ目のpipe()の引数でimagemin()を実行(引数は配列でオプション設定
  • オプション設定pngquantは品質65-80でスピード1、mozjpegの品質は80、imageminsvgogifsicleも実行
  • 二つ目のpipe()の引数でgulp.dest()を実行。引数は保存先のパス「/dest/img」
  • 最後にdone()を実行

watch設定

watch-filesgulp.task()に画像フォルダの監視設定を追加する

// 監視ファイル
gulp.task('watch-files', (done) =>  {
    gulp.watch(["./src/ejs/**/*.ejs", "./src/json/**/*.json"], gulp.task('ejs'));
    gulp.watch("./dest/*.html", gulp.task('browser-reload'));
    gulp.watch("./src/scss/**/*.scss", gulp.task('sass'));
    gulp.watch("./dest/css/*.css", gulp.task('browser-reload'));
    gulp.watch(["./src/ts/**/*.ts", "./src/json/**/*.json"], gulp.task('webpack'));
    gulp.watch("./dest/js/*.js", gulp.task('browser-reload'));
    gulp.watch("./src/img/**/*", gulp.task('imagemin')); // 追加
    gulp.watch("./dest/img/*", gulp.task('browser-reload')); // 追加
    done();
});
  • gulp.watch()で「/src/img」フォルダを監視して、変更があったらimageminを実行
  • gulp.watch()で「/dest/img」フォルダを監視して、変更があったらbrowser-reloadを実行

これで画像フォルダに変更があったら画像圧縮が実行されてブラウザがリロードする。

defaultのタスクにimageminを追加

defaultgulp.task()に画像圧縮のタスクを追加する

// タスク実行
gulp.task('default', 
    gulp.series(gulp.parallel(
        'watch-files', 'browser-sync', 'ejs', 'sass', 'webpack', 'imagemin'
    ), (done) => {
    done();
}));
  • gulp.parallel()の引数の中にimageminを追加する

これでgulp起動時にもimageminを実行する。

動作確認

gulpを実行

$ npx gulp

localhostの3000でブラウザが立ち上がる。 f:id:idr_zz:20201122161636j:plain

destの/imgフォルダにも画像ファイルが入っている。 f:id:idr_zz:20201122161743j:plain


試しにファイル名を変えてみよう。destフォルダの方の画像はいったん削除して f:id:idr_zz:20201122162101j:plain

ヘッダーの背景画像もリンク切れになる。 f:id:idr_zz:20201122162142j:plain


srcフォルダの画像のファイル名の拡張子を「.jpeg」から「.jpg」に変更 f:id:idr_zz:20201122162233j:plain

destフォルダにも「.jpg」の画像が保存される。 f:id:idr_zz:20201122162337j:plain


「_header.scss」の背景画像のパスも「.jpg」に変更

/* header */
.header {
    @include pageSize();
    padding: 80px 10px;
    background-image: url(../img/header_bg.jpg); // 拡張子変更
    background-size: cover;
    text-align: center;
    &__title {
        margin: 0;
        color: $text-color_w;
        text-shadow: 0 0 20px #000;
    }
}

「style.css」の背景画像も「.jpg」でコンパイルされている。

.header {
  width: 100%;
  max-width: 1000px;
  padding: 0 20px;
  margin: 0 auto;
  padding: 80px 10px;
  background-image: url(../img/header_bg.jpg);
  background-size: cover;
  text-align: center;
}

背景画像が再び表示された! f:id:idr_zz:20201122161636j:plain


圧縮前:srcフォルダの画像(28KB) f:id:idr_zz:20201122162715j:plain

圧縮後:destフォルダの画像(20KB) f:id:idr_zz:20201122162717j:plain

わずかだがサイズが下がっている。圧縮が行われていることがわかった!


今回の修正内容(GitHub)

※参考:画像圧縮設定を追加 · ryo-i/frontendMetaLanguage@9f4bb86 · GitHub

プレビュー画面(GitHub Pages)

※参考:メタ言語同時コンパイル(EJS、Sass(SCSS)、TypeScript)

最後に

ということでメタ画像コンパイル時に同時に画像の圧縮も実行できました。また、これによってコンパイル後のdestフォルダは手付かずで画像ファイルについてもsrcフォルダ内の作業で完結することができるようになりました。

このメタ言語開発環境、あんなこと、こんなこと他にもいろいろなことをやりたくなってきます。

  • gulpの修正時にNodeサーバを閉じなくていいいように監視したい(gulp-nodemon)
  • DBと接続するAPI設定を作りたい(Express)
  • Node環境の方もTypeScriptで型を付けて書きたい(gulpfile、Express共に)

ただ、やり始めるとキリがないし、何よりそろそろ具体的なアプリや作品を作りたいです。

当初やりたかったことは大方実現できたので、現時点でいったん最小構成のメタ言語セットを作って、そこに機能を足し算する形で進めていこうかな、とも考えています。

それではまた!


※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com