この記事はAizu Advent Calendar 2023の5日目だ。会津大のメンバーが投稿しているので是非みてほしい。
バックリンクとは被リンクの一覧のことだ。 あるページにおいて、自身がどのページがらリンクされているかを表示することで、 ページ間の移動を簡単にするという目的で設置されることが多い(あとはSEO的に強いとかなんとか)
記事がデータベースに保存してあるようなプロジェクトで作るのが一般的だと思う。
バックリンクをこのブログに実装した。Astroの機能を利用しているのでAstro専用である。
各ページでContent Collectionsをすべて解析することで、SSGに対応しつつdev serverにも対応した。
全体としては、markdownの解析を行ないフロントマターに順方向のリンク一覧を書き込むRehypeプラグインと、 astroコンポーネント内ですべてのmarkdownのフロントマターを読み、逆方向のリンクに変換する関数で構成される。
今回、このブログに実装する前に、3種類の設計を試した。
そして採用した、
それぞれに利点と欠点がある。それぞれを箇条書きする。
viteのプラグインを作成する方法
各ページでhtmlを解析する方法
rehypeプラグインを作成する方法
最終的に3番目の方法を選択したのはご存知のとおりである。
次のコードはrehypeのプラグインの一部。ここでhastを読み、フロントマターに書き込んでいる。
const forlinkNodes: hast.Element[] = [];
visit(tree, (node, _index, _parent) => {
if (node.type === 'element' && node.tagName === 'a')
forlinkNodes.push(node);
});
setVfileFrontmatter(file, {
forlink: forlinkNodes
.map(node =>
node.properties == null ?
{} :
node.properties
)
.map(properties => properties.href)
.filter((link): link is string => typeof link == 'string'),
});
そしてgetStaticPaths()
の中でフロントマターを読み、各ページでレンダリングする。
astro dev
を実行中、content collectionsの更新にあわせてバックリンクを再生成することができる。
export async function getStaticPaths() {
const entries = await getCollection("blog");
const backlinks = await getBacklinks([entries]);
return entries.map((entry) => ({
params: { slug: entry.slug },
props: {
entry,
backlink:
backlinks.get(`/${entry.collection}/${entry.slug}/`) ?? [],
},
}));
}
Astroに苦しめられた感が強い。
アドカレに衝動的に登録したが、ギリギリ間に合った。 もうすこし余裕をもって登録すべき。