category icon
2022-11-22
JavaScript - Nuxt3

nuxt3でビルド時に画像の変換をする方法

nuxt
3.0.0
profile
hikaru
Software Developer / DIY'er

vite のビルド(npm run dev/build/generate)時に画像の変換を実行する例です。
viteのプラグインを作成することで実現できます。

ビルド前 (変換対象の画像を指定する)
<img src="~/assets/img/example.jpg?mode=preview" />
ビルド後 (4pxにリサイズした後、base64に変換させる)
<img src="data:image/gif;base64,R0lGODlhBAAQAIIAAExpcSsnJiwnJismJSolJC0mJCcjIQAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFAAAAACwAAAAABAAQAAADDQi6phJrjUWivbbgfRMAOw==" />

実装例

img 要素の src 属性に指定する画像ファイルは、publicディレクトリを指定せずに assetsディレクトリ内の画像を指定すること。

app.vue
<template>
  <!--
    publicディレクトリを指定せず、assetsディレクトリ内の画像を指定する。
    ファイル末尾の"?mode=preview"をキーワードにviteプラグインに変換を指示させている。
   -->
  <img src="~/assets/img/example.jpg?mode=preview" />
</template>
nuxt.config.ts
export default defineNuxtConfig({
  // ↓今回は必要ないコード。アプリ独自の要素や属性にviteプラグインを適用させる場合はここに記載する。
  // vite: {
  //   vue: {
  //     template: {
  //       transformAssetUrls: {
  //         // 標準以外の要素や属性を使用する場合は、ここに要素と属性を指定する
  //         // 例:↓独自のAppImage要素(コンポーネント)のsrc属性に対してviteプラグインのtransform処理を適用させる
  //         AppImage: ["src"],
  //       },
  //     },
  //   },
  // },
});

viteの設定ファイル

vite.config.ts
import { defineConfig } from "vite";
import previewImagePlugin from "./vite/previewImagePlugin";

export default defineConfig({
  plugins: [previewImagePlugin()],
});

実際の vite プラグインの処理部分。今回は画像変換ライブラリの sharp を使用して 4px にリサイズしたものを base64 として返す処理となる。

vite/previewImagePlugin.ts
import { PluginOption } from "vite";
import sharp from "sharp";

export default function previewImagePlugin(): PluginOption {
  return {
    name: `previewImagePlugin`,

    async transform(code, id) {
      const { path, query } = parseId(id);

      if (query.mode !== `preview`) {
        return;
      }

      // 画像をリサイズする
      const buffer = await sharp(path).resize(4).gif().toBuffer();

      // リサイズした画像をbase64形式で返す
      const base64 = `data:image/gif;base64,${buffer.toString(`base64`)}`;

      return {
        code: `export default "${base64}";`,
        map: null,
      };
    },
  };
}

function parseId(id: string) {
  const index = id.indexOf("?");
  if (index < 0) return { path: id, query: {} };

  const query = Object.fromEntries(new URLSearchParams(id.slice(index)));
  return { path: id.slice(0, index), query };
}

以上、とりあえずのメモでした。