LoginSignup
4
0

この記事の概要

Next.js ではoutput: "export"を設定すると、通常の画像最適化は有効になりません。
next/imageを使用した際、次のようなエラーが出ます。

Error: Image Optimization using the default loader is not compatible with `{ output: 'export' }`.
  Possible solutions:
    - Remove `{ output: 'export' }` and run "next start" to run server mode including the Image Optimization API.
    - Configure `{ images: { unoptimized: true } }` in `next.config.js` to disable the Image Optimization API.
  Read more: https://nextjs.org/docs/messages/export-image-api

画像の最適化を諦めたくはないので、ライブラリを使って解決する方法を記事にしました。

基本的にはライブラリのドキュメント通りの記載をしていますが、一部私の解釈も入っています。
手元で試した限り動作的には問題ありませんでしたが、もし間違いなどがあればコメントをいただけると嬉しいです。

よく似たライブラリであるnext-export-optimize-imagesを試した記事も書きました。
ちなみに両方を比較した結果、next-export-optimize-images を選ぶかなあ、という印象です。

環境

主要なものだけ記載します。

依存関係 バージョン
next 14.2.3
next-image-export-optimizer 1.13.0
react 18.3.1
typescript 5.4.5

この記事で話題にするのは next-image-export-optimizer です。

インストールとセットアップ

コマンドを叩きます。

npm install next-image-export-optimizer

次にnext.config.mjsを編集します。
最低限の記載(すべてデフォルト値を使用する)なら次のようになります。

next.config.mjs
  /** @type {import('next').NextConfig} */
  const nextConfig = {
    output: "export",
+   images: { loader: "custom" },
+   transpilePackages: ["next-image-export-optimizer"],
  };

  export default nextConfig;

省略せず、すべてを記載すると次のようになります。
(ただしここで記載しているすべての値はデフォルト値のままなので、得られる結果は上に記載しているものと何も変わりません)

next.config.mjs
  const nextConfig = {
    output: "export",
+   images: {
+     loader: "custom",
+     imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
+     deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
+   },
+   transpilePackages: ["next-image-export-optimizer"],
+   env: {
+     nextImageExportOptimizer_imageFolderPath: "public/images",
+     nextImageExportOptimizer_exportFolderPath: "out",
+     nextImageExportOptimizer_quality: "75",
+     nextImageExportOptimizer_storePicturesInWEBP: "true",
+     nextImageExportOptimizer_exportFolderName: "nextImageExportOptimizer",
+     nextImageExportOptimizer_generateAndUseBlurImages: "true",
+     nextImageExportOptimizer_remoteImageCacheTTL: "0",
+   },
  }

デフォルト値から変えることが多そうなのはimageSizesdeviceSizesでしょうか。
ここに記載してある種類が多いほど書き出される画像数が増え、ビルド時間が伸びます。

画像にもよると思いますが、試しに作ってみた環境では 3 枚の画像を最適化するだけで 10 秒ほどかかってしまいました。


またpackage.jsonのスクリプトも書き換えます。

package.json
  "scripts": {
-   "build": "next build",
+   "build": "next build && next-image-export-optimizer",
  }

これにより、ビルド時にnext.config.jsでの指定にあわせて複数の画像が書き出されます。


最後にnext/imagenext-image-export-optimizerに置き換えます。

- import Image from "next/image";
+ import ExportedImage from "next-image-export-optimizer";
  import imgSrc from "path/to/image";
  
- <Image src={imgSrc} alt="Image description" />;
+ <ExportedImage src={imgSrc} alt="Image description" />;

ドキュメントに書いていないけど、実施しておいた方が良さそうなこと

開発時でも一度画像を書き出す必要がある

scripts のnext-image-export-optimizerを走らせないままnext devをすると、次のようになります。

<ExportedImage />public/images/nextImageExportOptimizerの中に画像ファイルがあることを期待しているのですが、見つからないためエラーになっている、という状態です。

開発環境での表示自体はできるのですが、画像の数だけエラーが増えるのでかなり見づらくなります。
解消するためには、次のどちらかを実施します。

  1. npm run devの前にnpm run buildをする
  2. devコマンドにnext-image-export-optimizerをセットにする

1 番目の内容は読んで字の如くなので省略します。
2 番目の内容は、scripts を次のように書き換えます。

package.json
  "scripts": {
-   "dev": "next dev",
+   "dev": "next-image-export-optimizer && next dev",
  }

なお、このやり方が正しいのかは怪しいです。

公式ドキュメントにもありませんし、私が試した限り挙動に問題が無かっただけで、環境などが違えば何かが起きるかもしれません。

ただ「開発する前に一度ビルドする」といった、人間の記憶に頼ったやり方よりは良いかな?と思っている次第です。

.gitignoreに画像の書き出し先を指定しておいた方が良さそう

ここまでの設定のままだとpublic/images/nextImageExportOptimizerにある画像がすべて git 管理下に置かれます。

完全にダメということでもないと思いますが、画像を追加・削除するだけで Pull Request の diff がかなり増えてしまうなど、面倒なことも多そうです。

実際、example として用意されているコードでは .gitignorepublic/images/nextImageExportOptimizerが記載されています。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0