🎨

Next.js SSGでImageタグのエラーに対処する方法

2023/04/19に公開

Imageタグエラー

Next.jsで静的サイト生成(SSG)を行う際に、Imageタグでエラーが発生しました。
エラー内容は以下の通りです。

Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
  Possible solutions:
    - Use `next start` to run a server, which includes the Image Optimization API.
    - Use any provider which supports Image Optimization (like Vercel).
    - Configure a third-party loader in `next.config.js`.
    - Use the `loader` prop for `next/image`.

next exportはNext.jsデフォルトローダーのImage Optimizationと互換性がなく、要は<Image>タグはSSGには使えないようです。

仕方がないので画像を<img>タグに置き換えてビルドするとにしました。

ESLintエラー

今度はESLintのエラーが発生しました。

warn  - Statically exporting a Next.js application via `next export` disables API routes and middleware.
This command is meant for static-only hosts, and is not necessary to make your application static.
Pages in your application without server-side data dependencies will be automatically statically exported by `next build`, including pages powered by `getStaticProps`.
Learn more: https://nextjs.org/docs/messages/api-routes-static-export

next exportは静的ホスト専用でAPIルートとミドルウェアが無効化されてそれの影響らしい。
こちらはESLintの対象から除外することで回避しました。

.eslintrc

{
  "extends": "next/core-web-vitals",
+  "rules": {
+    "@next/next/no-img-element": "off"
+  }
}

画像が表示されない

これでビルドは通ったのですが、今度は画像が正しく読み込まれない事象が発生しました。
Imageからimgタグに置き換えたことで、正しいPathが生成されなくなったみたいです。

alt

Pathを考慮したStaticImageというcomponentを作成して、imgタグと置換して対応しました

component/StaticImage.tsx

import React from 'react'
const isProd = process.env.NODE_ENV === 'production'
const prefixPath = !isProd ? '/portfolio' : ''

function withPrefix(path: string) {
  return `${prefixPath}${path}`
}

interface StaticImageProps {
  src: string
  alt: string
  className?: string
  width?: number
  height?: number
}

export default function StaticImage({ src, alt, ...props }: StaticImageProps) {
  return <img src={withPrefix(src)} alt={alt} {...props} />
}

pages/index.tsx

import Image from "next/image";
import StaticImage from "../component/StaticImage";
import { Inter } from "next/font/google";

const inter = Inter({ subsets: ["latin"] });

export default function Home() {
  return (
    // ...
    <StaticImage
      src="/vercel.svg"
      alt="Vercel Logo"
      className="dark:invert"
      width={100}
      height={24}
    />
    // ...
  );
}

これにより、事象は解消しました!

alt

ただ画像周りはまだ色々問題が出てきそうですね。。。

GitHubで編集を提案

Discussion