この記事の概要
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
を編集します。
最低限の記載(すべてデフォルト値を使用する)なら次のようになります。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export",
+ images: { loader: "custom" },
+ transpilePackages: ["next-image-export-optimizer"],
};
export default nextConfig;
省略せず、すべてを記載すると次のようになります。
(ただしここで記載しているすべての値はデフォルト値のままなので、得られる結果は上に記載しているものと何も変わりません)
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",
+ },
}
デフォルト値から変えることが多そうなのはimageSizes
とdeviceSizes
でしょうか。
ここに記載してある種類が多いほど書き出される画像数が増え、ビルド時間が伸びます。
画像にもよると思いますが、試しに作ってみた環境では 3 枚の画像を最適化するだけで 10 秒ほどかかってしまいました。
またpackage.json
のスクリプトも書き換えます。
"scripts": {
- "build": "next build",
+ "build": "next build && next-image-export-optimizer",
}
これにより、ビルド時にnext.config.js
での指定にあわせて複数の画像が書き出されます。
最後にnext/image
をnext-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
の中に画像ファイルがあることを期待しているのですが、見つからないためエラーになっている、という状態です。
開発環境での表示自体はできるのですが、画像の数だけエラーが増えるのでかなり見づらくなります。
解消するためには、次のどちらかを実施します。
-
npm run dev
の前にnpm run build
をする -
dev
コマンドにnext-image-export-optimizer
をセットにする
1 番目の内容は読んで字の如くなので省略します。
2 番目の内容は、scripts を次のように書き換えます。
"scripts": {
- "dev": "next dev",
+ "dev": "next-image-export-optimizer && next dev",
}
なお、このやり方が正しいのかは怪しいです。
公式ドキュメントにもありませんし、私が試した限り挙動に問題が無かっただけで、環境などが違えば何かが起きるかもしれません。
ただ「開発する前に一度ビルドする」といった、人間の記憶に頼ったやり方よりは良いかな?と思っている次第です。
.gitignore
に画像の書き出し先を指定しておいた方が良さそう
ここまでの設定のままだとpublic/images/nextImageExportOptimizer
にある画像がすべて git 管理下に置かれます。
完全にダメということでもないと思いますが、画像を追加・削除するだけで Pull Request の diff がかなり増えてしまうなど、面倒なことも多そうです。
実際、example として用意されているコードでは .gitignore
にpublic/images/nextImageExportOptimizer
が記載されています。