発生した事象:Astroブログでリンクの「カード」が出ない
Astro で構築した本ブログの記事を Discord や X (旧Twitter) に投稿した際、期待していたリッチなプレビュー(OGP画像の表示)が行われず、ただのテキストリンクになってしまう問題に直面しました。
前回の記事でメタタグの実装を行ったはずですが、なぜ外部サービスから認識されないのか。調査の結果、Astro 環境における「URLの相対パス」の扱いに原因がありました。
原因:クローラーは「相対パス」を解釈できない
ブラウザで Astro サイトを閲覧している分には、/favicon.png といった相対パスでも問題なく画像が表示されます。しかし、外部のクローラー(Discordのbot等)は、サイトのドメインコンテキストを持たないため、リソースを特定するために完全な絶対URLを必要とします。
私の BaseLayout.astro の実装では、以下のように記述していました。
<!-- 改善前:Discord等では画像が見つからない -->
<meta property="og:image" content="/hero.png" />
これでは、クローラーは「どこのサーバーの /hero.png なのか」が分からず、プレビューの生成を諦めてしまいます。
解決策:Astro.url を活用した絶対URLの生成
Astroには、現在アクセスしているページの情報を取得するための便利なAPI Astro.url が用意されています。
これを利用して、画像パスやカノニカルURLを動的に絶対URLへと変換するように修正しました。
BaseLayout.astro の修正
---
// BaseLayout.astro の Frontmatter内
const { title, description, image } = Astro.props;
---
<head>
<!-- URLを絶対パスで明示 -->
<link rel="canonical" href={Astro.url} />
<meta property="og:url" content={Astro.url} />
<!-- 画像パスを絶対URLへ変換 -->
<meta property="og:image" content={new URL(image || '/favicon.png', Astro.url)} />
<!-- Twitter用のカード設定 -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content={new URL(image || '/favicon.png', Astro.url)} />
</head>
ここで重要なのは new URL(image, Astro.url) という書き方です。これによって、image がどのようなパスであっても、現在のページのベースURLに基づいた正しい絶対URLが生成されます。
根拠としたドキュメント
今回の実装は、Astroの公式ドキュメントにある以下の仕様に基づいています。
- [Astro.url](https://docs.astro.build/ja/reference/api-reference/#astrourl): 現在のリクエストのURLを取得するための標準的な手段です。カノニカルURLの設定に必須とされています。
- [Astro.site](https://docs.astro.build/ja/reference/api-reference/#astrosite):
astro.config.mjsで定義したsiteプロパティを参照します。ビルド時にURLが確定している環境(本番環境など)でのベースURLとして機能します。
まとめ
今回の修正によって、Discord等の外部サービスに対して「このURLが正当なソースで、この絶対パスに画像がある」という情報を不備なく伝えられるようになりました。
SEOメタタグを追加する際は、常に「外部の目線(クローラー)」でパスを捉え、絶対URLを指定することが鉄則です。