no7.space
🖼️

リンクカードのOGP表示を next/image にする

前回リンクカードのコンポーネントを作ったのですが、そのときは普通に HTML の img 要素を使ってました。
ですが、これを Copilot にレビューしてもらったところ、今回のように外部の画像を src に指定する場合は、画像をプロキシしたり、 next/image を使ったほうがよいとのことでしたので、今回はここを修正していきます。

copilot review

前回:

next/image に切り替える

next/image は Next.js 組み込みの画像コンポーネントで、画像の最適化や管理を用意にするための様々な仕組みが用意されています。
img とプロパティも似ているので、付替えも比較的容易かなとおもいます。

ということで、早速差し替えます。

+import Image from 'next/image'
// ... 中略
-<img
+<Image
  className={styles['link-card-thumbnail--image']}
+ fill
  sizes="(max-width: 768px) 120px, 320px"
  src={siteMeta.image}
  alt={siteMeta.title || ''}
/>

next/image は必ず widthheight の指定が必要なのですが今回、画像のサイズが不明1なので、fill を使うのと、width/height の代わりに sizes の指定を行います(省略した場合は 100vw を指定したものとして扱われるみたいです)。

Invalid src prop on next/image エラー

さて、これで img から Image に切り替わったのですが、読み込もうとすると次のようにエラーになってしまいました。

Runtime Error

Invalid src prop (https://no7.space/blog/01K41A4QYX2Q2XRE6ZH6JPQEKC/og.png) on `next/image`, hostname "no7.space" is not configured under images in your `next.config.js`
See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host

これは、next/image で外部のリソースを表示する場合、事前に許可されたホストの画像意外読み込まないようになっているためみたいです。

で、これを解消するためには、next.config.ts で許可リストを作ればOKです。
ただ、今回のブログコンテンツなど、参考記事のリンクカードを作る場合、リンク先全てのホストを指定するのはあまり現実的じゃありません。

なので、今回はワイルドカード指定をしてしまうことにしました。2
(一応、プロトコルは https 限定ですが、ほかは全て許容しています)

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**',
        port: '',
        pathname: '/**',
      },
    ],
  },
}

そしたら当然ツッコミが入りました。

alt text

CSS 調整

最後に、スタイルを少し調整します。
まず、Image コンポーネントに object-fit: cover; を指定します。
あと、fill にしたら、 position: absolute; がついてページ上部に全部張り付いちゃったので、親要素に position: relative もつけました。

.link-card {
  &-thumbnail {
    width: $thumbnail-width;
    position: relative;

    &--image {
      object-fit: cover;
    }
}

参考

Footnotes

  1. 一応今回に限っては OGP は規格があるにはあるんでそれをアテにしてもよさそうではありますが、守ってない場合も考慮して…

  2. 本来ならセキュリティのこととか考えての機能なので、ちゃんと設定すべきだとはおもうのですが…