EJSにwebp生成と画像圧縮の自動化を追加する

[ node.jsで画像の圧縮とwebp生成を自動化する](https://zenn.dev/rik9228/articles/256d26cbfcaf1e)をEJSテンプレートに追加しました。
figmaから書き出し→サルワカなどのサイトでwebpに変換...:innocent:の作業なくなり、効率がぐんと上がりました。

今回はそのjsを読み解いていこうとおもいます。

# パッケージのインストール
下記パッケージをインストールします。
nodeは`16.0.0`にバージョンアップしました。

```json
{
"imagemin-keep-folder": "^5.3.2",
"imagemin-mozjpeg": "^10.0.0",
"imagemin-pngquant": "^9.0.2",
"imagemin-svgo": "^9.0.0",
"imagemin-webp": "^6.0.0",
}
```
ターミナルで下記コマンドを打つとインストールされます
```
npm install --save-dev imagemin-keep-folder imagemin-pngquant@9.0.0 imagemin-webp@6.0.0 imagemin-svgo@9.0.0 imagemin-mozjpeg imagemin-gifsicle
```

# プロジェクト直下に imagemin.js を作成
imagemin.jsに処理内容をかいていきます。

## パッケージをインポート
[ node.jsで画像の圧縮とwebp生成を自動化する](https://zenn.dev/rik9228/articles/256d26cbfcaf1e)では、`require()`を使ってますが、`requireはESモジュールスコープで定義されていませんので、代わりにimportを使用してください。`というエラーになってしまったので、言われるがままに`import`で対応しました。
また、`import`を使うためにpackage.jsonに`"type": "module",`を追記しました。

```javascript
import imagemin from 'imagemin-keep-folder';
import imageminPngquant  from 'imagemin-pngquant';
import imageminWebp  from 'imagemin-webp';
import imageminSvgo  from 'imagemin-svgo';
import imageminMozjpeg  from 'imagemin-mozjpeg';
import imageminGifsicle  from 'imagemin-gifsicle';
```

## 画像のパスを変数化
画像のパスを変数にしておきます。
```javascript
//圧縮したい画像パス
const srcDir = "./src/assets/img/**/*.{jpg,jpeg,png,gif,svg,ico}";
//圧縮された画像の行く先パス
const outDir = "./dist/assets/img/**/*"; 
```

## webp生成のための関数を定義

```javascript
const convertWebp = (targetFiles) => {
  imagemin([targetFiles], { // パッケージ：imagemin-keep-folder使用
    use: [imageminWebp({ quality: 50 })], // パッケージ：imagemin-webp使用
  });
};
```
`imagemin`とは最初にimportしたパッケージの`imagemin-keep-folder`です。
ディレクトリ構造を維持した状態で、吐き出し先に最適化した画像群を送ってくれます。
画像パスとして引数`[targetFiles]`が指定されています。
最適化の処理として`use: [imageminWebp(~`の部分で、パッケージの`imagemin-webp`を使ってwebpを生成しています。

※quality（デフォルトは75）は指定しないとまれに処理が通らない場合があるそうです。50が丁度いいみたい


## 処理

```javascript
imagemin([srcDir], { // 1. 圧縮したい画像パスを指定
  plugins: [ // 2. 圧縮処理をするパッケージを記載
    imageminMozjpeg(),
    imageminPngquant(),
    imageminGifsicle(),
    imageminSvgo(),
  ],
  replaceOutputDir: (output) => { // 3. フォルダー構造をカスタマイズ  
    return output.replace(/img\//, "../../dist/assets/img/");
  },
}).then(() => { // 4. プロミスチェーンで下記処理をつなげる
  convertWebp(outDir);
  console.log("Images optimized!");
});
```

1. `imagemin-keep-folder`である`imagemin`に変数にしておいた圧縮したい画像パス`srcDir`を指定しています
2. `plugins: [~`に圧縮処理をしてくれるパッケージを記載しています。
※`plugins:`は`use:`の複数用なだけなのかuseをpluginsに変えても処理が通りました。
3. `replaceOutputDir: `で圧縮後の画像のフォルダ構造を、`/img/`から2階層上の`../../dist/assets/img/`にカスタマイズされてます。
4. プロミスチェーンで、**圧縮後の画像をwebp変換する`convertWebp(outDir);`** と、コンソールに「Images optimized!」を出力する処理をつなげています。

# EJSに imagemin.js の自動実行を追加

imgを監視して自動で imagemin.js を実行するように package.json に追加しました。
```json:
"watch:img": "chokidar \"src/assets/img/**/*\" -c \"node imagemin.js\" --initial",
```

```html
chokidar \" 監視対象のファイル \" -c \" 監視対象ファイルが変更したあとに実行するコマンド \" -–initial
```

> `-c`はcommandの略、`--initial`はwatchコマンド実行後にスクリプトを１回実行するという意味です。
[EJS CLIでEJSを自動コンパイルする方法 \| zumilog](https://zumilog.org/ejs-autocompile/#%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E8%A8%98%E8%BF%B0%E3%81%99%E3%82%8B)

# `<symbol>`を使ったSVG画像の圧縮がうまくいかない
`<symbol>`で囲んだSGVを`<use>`で出力させSVG画像を使い回す方法をよくやるのだが、これを圧縮すると、SVGコードが消えてしまいました。
SVGはもともと軽いし...ということで、一旦`imagemin-svgo`のSVGの圧縮はしないで使用しています。
[【SVG画像】1つの画像ファイルで複数の色違い画像を使いまわす \- Qiita](https://qiita.com/super-mana-chan/items/3d27b66c8ba0c633ca76)


# 参考サイト
https://zenn.dev/rik9228/articles/256d26cbfcaf1e

https://zumilog.org/ejs-autocompile/#%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E8%A8%98%E8%BF%B0%E3%81%99%E3%82%8B

https://www.npmjs.com/package/imagemin-keep-folder