Gatsby製ブログにmdx-js/reactとIframely APIでリンクカード対応
長らく、個人サイトをGatsbyで作ったまま放置で、ブログに貼り付けたURLがテキストリンクのままで味気なかったので、いい加減リンクカード対応しました。
とりあえず、マークダウンファイル(md
, mdx
)にプロトコル付きのURLを入力すると、サムネイル、タイトル、ディスクリプションが表示されるようにしました。
完成したはこちら↓↓↓
目指す状態
マークダウンに貼る形式を工夫すれば、リンクカード表示は大して手がかかるものではないのですが、非エンジニアでも使えるように、何も考えずに、記事の中にURLを貼り付けられた場合に動的にサムネイルとタイトルが表示されてちゃんとスタイルが当たっている状態を目指しました。
必要なプラグインをインストール
ブログはGatsby製です。
まず、GatsbyのマークダウンからHTMLに生成するフローの中で、HTMLをカスタマイズする必要があります。
公式によると、マークダウンの中でタグをカスタマイズしたい場合は、@mdx-js/react
というパッケージを使うといいよと記載してありましたので、こちらのパッケージを導入しました。
yarn add @mdx-js/react
こちらは後ほど組み込みますので、とりあえずここでは導入のみ。
iframely API key生成
リンクカードを取得するために、URLからサムネイル、タイトル情報やディスクリプション情報を取得する必要があります。
今回は、iframely APIを使って、oEmbed形式の情報を取得するようにしました。
iframely APIを利用するためには、アカウントを作成してAPI keyを生成する必要があったので、アカウント登録を行い、API keyを生成します。
API keyが生成されれば後は、URLを以下の形式のAPIのパラメータとして送れば、oEmbed形式の情報が取得できます。
APIリクエスト
iframe.ly/api/oembed?url={URL}&api_key={API_KEY}
APIレスポンス
リンクカード開発
これで準備が整ったので、いよいよリンクカード開発です。
リンクカードコンポーネント
リンクカード生成コンポーネントを作成します。
CardLink.jsx
import React, { useState, useEffect } from 'react'
const CardLink = ({ props }) => {
// リンクカード化するかどうかのチェックはプロトコルの有無で判断
const checker = props.children.match(/(http)?/)[1] !== undefined
const [embed, setEmbed] = useState({})
const getEmbed = async () => {
const data = await fetch(`https://iframe.ly/api/oembed?url=${props.children}&api_key=xxhogezzfugoyy...`)
.then(res => res.json())
.catch(error => error)
setEmbed(data)
}
useEffect(() => {
checker && getEmbed()
}, [])
return (
<>
{
checker ? (
<a href={embed.url} target='_blank'>
<div>
<div>
<div style={{ background: `center / contain no-repeat url(${embed.thumbnail_url})` }}></div>
</div>
<div>
<div>{embed.title}</div>
<div>{embed.description}</div>
</div>
</div>
</a>
) : (
<a href={props.href} {...props}>{props.children}</a>
)
}
</>
)
}
export default CardLink
今回は、リンクとして判断される、<a>
に対してカスタマイズを行います。
マークダウンで、テキストリンクとして作成されているものは除外したかったので、リンクカード対応させるかどうかは、http
プロトコルが含まれているかどうかというのを条件にしています。
仕様
No カードリンク → そのままテキストリンクとして返す。
[テキストリンク](https://hoge.com)
OK カードリンク → カードリンク用のDOMで返す。
https://hoge.com
iframelyには、HTMLを返するAPIも用意されていますが、今回はスタイルをオリジナルで当てたかったので、サムネイル画像、タイトル、ディスクリプション等を取得して後は自分でスタイルを当てています。(オリジナルCSS部分は省略しております)
記事ページの開発
マークダウンのカスタマイズは、@mdx-js/react
のMDXProvider
で行います。
対象のタグをカスタマイズ用のコンポーネントに引き渡します。
{mdx.slug}.jsx
import { MDXProvider } from '@mdx-js/react'
<MDXProvider
components={{
a: props => <CardLink props={props} />
}}
>
<MDXRenderer>
{data.mdx.body}
</MDXRenderer>
</MDXProvider>
以上で、リンクカード化対応完了です!
さいごに
今回は、iframely APIを使って、oEmbed形式のデータを取得してリンクカードをオリジナルで作成しました。
大変便利なAPIで、個人ブログとして対応させるだけなれば、十分ですが、、今のブログをOSS化できるようにしたいなぁと考えているので、API keyを必要とする構成では若干難があります。
この辺りはまだまだ改善が必要そうです。
参考資料
Discussion