【Astro】自動で情報を取得するリンクカードコンポーネントを作る

目次

執筆時の作業環境は以下のとおりです。

  • MacOS: Sonoma 14.2.1
  • Node.js: v21.6.1
  • npm: v10.2.4
  • Astro: v4.4.0
  • open-graph-scraper: v6.5.0

はじめに

ブログの記事内に外部サイトへのリンクを貼るとき用にリンクカードを作成しました。

↓これです

Astro

Astro builds fast content sites, powerful web applications, dynamic server APIs, and everything in-between.

ビルド時にリンク先の情報を読み取ることで、画像やタイトルなどのデータを入れた状態でHTMLを生成しているので、ページロード時に毎回情報を取得するよりもパフォーマンス面で優れています。

情報を取得する方法

Open Graph Scraper をインストール

Astroのビルド時のスクリプトはNode.js上での動作なので、通常のJavaScriptのDOMPerserインターフェイスなどは使用できません。

今回はDOMを解析するために Open Graph Scraper(以下OGS)というライブラリを使用します。

open-graph-scraper

Node.js scraper module for Open Graph and Twitter Card info. Latest version: 6.8.0, last published: 9 days ago. Start using open-graph-scraper in your project by running `npm i open-graph-scraper`. There are 66 other projects in the npm registry using open-graph-scraper.

npm i --save open-graph-scraper

OGSで情報を取得する

OGSで情報を取得する関数は以下のとおりです。関数を呼び出すときに引数に渡すURLはpropsとして受け取ります。

---
import ogs from 'open-graph-scraper'

async function getOpenGraphData(url: string) {
  const options = { url }
  try {
    const { result } = await ogs(options)
    return result
  } catch (error) {
    console.error('Error fetching Open Graph Data:', error)
    return {}
  }
}
---

取得した情報を使用する

取得した情報は、コンポーネントのテンプレート部分で使っていきます。

基本的にはpropsにはslugというURL情報しか渡さなくてもいいのですが、必要があればcaptionにリンクのキャプションを表示できる他、titledescriptionimageを手動で設定することもできるようにしました。||演算子を使うことで、手動で設定した内容が優先的に反映されるようにしています。

また、OG画像が取得できなかったときはNO IMAGEと書かれた画像が表示されるようになっています。

---
// インポート
import ogs from 'open-graph-scraper'
import { Icon } from 'astro-icon/components'
import Noimage from '@/images/noimage_placeholder.png'

// propsの指定
interface Props {
  slug: string
  caption?: string
  title?: string
  image?: string
  description?: string
}

// propsを分割代入
const { slug, caption, title, image, description } = Astro.props

// OGSで情報を取得
async function getOpenGraphData(url: string) {
  const options = { url }
  try {
    const { result } = await ogs(options)
    return result
  } catch (error) {
    console.error('Error fetching Open Graph Data:', error)
    return {}
  }
}

// 情報を変数に格納(自分でpropsにせってした場合はそれが優先される)
const websiteData = await getOpenGraphData(slug)
const ogImage = image || websiteData?.ogImage?.[0]?.url || Noimage.src
const ogTitle = title || websiteData?.ogTitle || 'タイトルの取得に失敗しました'
const ogDescription = description || websiteData?.ogDescription || ''
---

<a href={slug} target="_blank">
  {caption && <p>{caption}</p>}
  <div>
    <div>
      <img src={ogImage} alt="" />
    </div>
    <div>
      <h1>{ogTitle}</h1>
      <p>{ogDescription}</p>
    </div>
    <Icon name="mdi:open-in-new" width={24} height={24} />
  </div>
</a>

コードが煩雑になるのでスタイルの部分は省略しています

コンポーネントを使用する

完成したコンポーネントはimport LinkCard fron 'path/to/file/LincCard.astro'でインポートし、以下のように記述して使用します。

<LinkCard slug="https://astro.build/" caption="キャプションです" />

↓このコードで生成されるリンクカードがこちらです。

キャプションです

Astro

Astro builds fast content sites, powerful web applications, dynamic server APIs, and everything in-between.

おわり

自動で情報を取得するリンクカードのコンポーネントの作り方でした。

OGSは初めて使ったのですが、簡単にOGPデータを取得できて便利でした。画像が取得できなかったらどうするかなど、作りながら出てきた問題に逐一対処するのも楽しかったです。

以上