koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

Next.jsのpublic配下の画像をS3から配信したら画像が表示されなくなった

<Image src="/images/hoge.png" alt="" ... />

Next/Imageでの↑ように画像表示をしている状態で画像の配信構成を変えたら表示が全滅した。

before

flowchart LR
    UA --> CloudFront
    CloudFront -- default --> Next.js

after

flowchart LR
    UA --> CloudFront
    CloudFront -- default --> Next.js
    CloudFront -- /images/* --> S3

にしてNext.jsのコンテナイメージ*1からは画像を消し飛ばした。

そうしたら

The requested resource isn't a valid image.

表示になった。

ちゃんと裏付けは取っていないのだけれど、Next/Imageのloaderはサーバー絶対パス*2指定された画像は自身の実行環境のファイルシステムから探すのだろう。それはそうだ。スキーム、ドメインは書かれていないし、loaderの実行環境ではそれらが何だったのかは本質的には分からない。

※Next/Imageは任意の画像最適化処理、ローダに画像のURLを渡してくれる、既定のローダではhttps://example.com/_next/image?url=%2Fimages%2Fhoge.png&w=1920&q=75のようなURLでローダを呼び出す(img要素のsrc属性に指定する)。

Next/Imageに限らず、画像を動的にオプティマイズする際には画像の指定を絶対URL*3で指定するのが基本なのだろう。

Next/Imageでは例外的にpublic配下に置いて自分の支配下にある画像も指定できると捉えるのが良さそうだった。

で、その場合は支配下にあるリソースは実行環境にちゃんと配置しなくてはならない。

静的ファイルやろ! と/_next/static配下と同じノリでオブジェクトストレージに逃がしたのがいけなかった。

そんな感じ。

*1:コンテナでNext.jsを動かしていた

*2:呼び方違うかもだけれど要は/images/hoge.pngのような指定

*3:httpsから始まる完全なURL