Astroでdev環境でだけ動的生成画像が404になる

trailingSlashをalwaysにしたらdevでだけ動的生成画像が404になった

正確には、

  • astro.config.mjstrailingSlash: alwaysにすると
  • dev環境でだけ
  • [slug].png.ts等で動的生成している画像のパス末尾にもスラッシュがつく

です。

trailingSlashについては公式リファレンスを参照。

つまり、OGP画像が /ogp/post1.png/ みたいなパスになるということです。なんじゃそりゃ。

しかもこの状況で/ogp/post1.png(末尾にスラッシュがないほう)にアクセスした場合、404に本来出るはずの「trailingSlashをalwaysにしてるでしょ、正しくはこっちですよ」みたいな親切な忠告が出ません。

親切なほうの404

Your site is configured with trailingSlash set to always. Do you want to go to /blog/ instead?

こういう気の利いた404が、ページでは出るのに画像だと出ません。
おかげで何が起きてるか気付くまでにすごい時間を要しました……。

ということで悲しみを供養すべく記事にしています。

この記事の環境

  • Astro:5.16.15

読まなくてもいい経緯

無駄に長いので畳んでおきます

そう、私はただこういう、内部リンク用のリンクカードを作ろうとしていただけだったのです。1

ChatGPTくんに概要を伝えてざっと作ってもらったものの、情報が取得できるページとそうでないページがありました。
原因ははっきりしており、通常ページとContent Collectionsのページ(ブログ記事等)とで、パス末尾のスラッシュの有無が揃っていなかったのが問題でした。

で、じゃあURLの正規化的なやつをしたほうがいいか~という流れになり、勧められるまま、軽い気持ちでtrailingSlash: alwaysを追加してしまったのです。

情報は問題なく取得できるようになりました。これでもう大丈夫だろうと安心して、私はremarkのプラグインを作りました。内部リンクカードのコンポーネントができあがったので、それを独自記法でさっくり挿入できるようにしたかったからです。
独自記法をプラグインで独自タグに置き換えて、それをmdxのコンポーネント差し替えでAstroのコンポーネントに差し替えるようにまでしてやりました。

差し替えはできた。満足。これがやりたかった。

しかし、よくよく確認してみると、ChatGPTくんに作ってもらったリンクカードはサムネをhttps://~から読みに行っているではありませんか。2
いや内部リンクって言ってるんだから空気読んで相対パスにしてくれよ、と思いつつも修正しました。

……さっきまで出てたサムネ画像が表示されない。

いや、全部ではない。ブログ記事へのリンクカードだけ表示されない

直接画像のパスにアクセスしても404になる。いや、さっきまでそこにあったのに!?

しかしビルドでは正常に動作している…!

さらに悪いことに、コンポーネントの構成をリファクタリングしたばっかりだったり、パッケージを一気にアップデートしまくったりしたあとでした。なにかが破壊されてそうな心当たりがそこかしこにいっぱいありました。
なにも考えずに気になったことをいきなりやるからこうなるのです。

なんせ、作っていたリンクカードはローカルのOGPを全然読んでいなかったわけで、つまりこの一連の作業のいつから壊れていたのかもわからないのです。

trailingSlashのことはすっかり忘れ、リファクタリングでパスが壊れてないか確認してまわったり、gitを辿ってアップデートを巻き戻したり、いろいろなことを試しました。

肝心のOGPを生成するコード自体は一行も変更していない。
しかもOGP以外の、固定パスで生成している画像は普通に表示されるのです。トップ用のogp.png.tsとかは。

なにかが間違っているんだろうけどなにが間違ってるのか全然わからない。
しかもビルドではなにも問題がない!
そりゃmainブランチでは動いてるけどこれ一体どこまで巻き戻せばいいんだ……。

途方に暮れながら藁にも縋る思いでVScodeのチャット欄からAIに泣きついたところ(なんと今までほぼ使ったことがなかった)、mainでは動いてたんなら設定変えたのが原因でしょ、画像パスにスラッシュ足してみ(意訳)と言われ、
そんなバカなと思いながら足したら普通に表示されてひっくり返った、という流れでした。

.pngのあとにスラッシュ打ったのなんて人生で初めてだよ!
そんな発想なかったよ!ありがとうAIくん!

でAIくんに、じゃあそれ直してください!と頼んだんですが、なんか堂々巡りになって結局修正はしてくれませんでした。

というわけで自分で以下のようなしょうもない回避策を書きました。おわり。

とりあえずの対策

特定の拡張子だけtrailingSlashを除外する、みたいな設定はないようです。
たぶん。おそらく。自分とChatGPTくんが探した限りでは。

そうなると設定を戻す以外に正直どうしようもないのですが、そういうわけにもいきません。

ということで、dev環境でだけ画像パスの末尾にスラッシュを足すようにしました。あまりにもザ・応急処置ですが…。

LinkCard.astro
// trailingSlash:alwaysがdevではpngの動的生成にも効いてしまう問題の対策
if (import.meta.env.DEV) {
ogpPath += "/"
}

はい。

今回は動的生成画像を使うのが内部リンクカードだけにはっきり限られており、他に困る場面もないのでこれで良しとします。

なんかいい方法があったら教えてください…。


  1. 一応完成はしています。見た目は外部用のリンクカードと合わせてあります。

  2. そりゃhtmlを直接パースすればそうなる。
    というか、この時点では実はパース先がAstro.siteになっていてメタ情報全部webから持ってきていたという。
    内部リンクってずっと言ってるのになんでAstro.urlにしてくれなかったの…。