シリーズ目次 前章: 08. AstroPaperの配色テーマをカスタマイズする 次章: 10. AstroPaperでOG画像の自動生成とSEO
Table of contents
Open Table of contents
この章のねらい
AstroPaperには、サイト内検索とRSSフィード、サイトマップ、robots.txt が最初から入っています。どれも、読者や検索エンジンが記事にたどり着くための入口です。それぞれがいつ作られてどう使われるのかを見ていきます。
サイト内検索(Pagefind)
静的サイトで全文検索ができる理由
全文検索には普通、検索用のサーバーかデータベースが要ります。ところがAstroPaperは静的サイトで、配信されるのはHTMLファイルだけです。
Pagefind はこの制約をこう解きました。
- ビルドが終わった後のHTMLファイルを読む
- そこから検索用の索引(インデックス)ファイルを作っておく
- 読者が検索したとき、ブラウザが必要な索引だけを取得して絞り込む
索引は語ごとに細かく分割されているので、記事が増えてもブラウザが読み込むデータ量はあまり増えません。サーバーなしで、実用的な速度の全文検索が成立する。これがPagefindです。
索引が作られるタイミング
索引はビルドの後半で作られます。package.json の build を再掲します。
{
"scripts": {
"build": "astro check && astro build && pagefind --site dist && cp -r dist/pagefind public/"
}
}package.json
3番目の pagefind --site dist が索引を作る処理です。dist/ に書き出されたHTMLを走査するので、ビルドが終わっていなければ索引は存在しません。
4番目でその索引を public/ へコピーしているのは、次に pnpm dev を起動したときにも検索を試せるようにするためです。
開発サーバーだけでは検索結果が出ません。検索欄に、一度ビルドしてくださいという趣旨の警告が出ます。不具合ではなく仕様です。
何が索引に入るのか
Pagefindは、data-pagefind-body という目印が付いた範囲だけを索引化します。記事詳細ページのコードを見ると、<main> にこの属性が付いています。
<main id="main-content" class:list={[...]} data-pagefind-body>src/pages/posts/[...slug]/index.astro
つまり検索対象は記事本文のページだけです。一覧ページもタグページも索引に入りません。同じ記事が複数のページから重複して見つかるのを防いでいます。
さらに、記事内でも索引に入れたくない部分には data-pagefind-ignore を付けられます。テーマでは前後の記事へのナビゲーションに付いています。
<div data-pagefind-ignore class="my-8 grid grid-cols-1 gap-6 sm:grid-cols-2">src/pages/posts/[...slug]/_components/AdjacentPostNav.astro
隣の記事のタイトルが検索結果に紛れ込まないようにするための配慮です。
索引に入る範囲と入らない範囲を並べると、設計の意図が見えてきます。
検索UIの読み込み方
src/pages/search.astro は、検索UIをページ表示と同時には読み込みません。
const onIdle = window.requestIdleCallback || (cb => setTimeout(cb, 1));
onIdle(async () => {
const { PagefindUI } = await import("@pagefind/default-ui");
// ...
});src/pages/search.astro
requestIdleCallback は、ブラウザの手が空いたときに実行する仕組みです。おかげでページの表示速度を落とさずに検索機能を用意できます。
検索語とURL
検索すると、URLが /search/?q=astro のように変化します。
processTerm: function (term: string) {
params.set("q", term);
history.replaceState(history.state, "", "?" + params.toString());
// ...
}src/pages/search.astro
この仕組みにより、検索結果のURLを共有したり、ブラウザの戻る操作で検索結果に戻ったりできます。また、/search/?q=astro へ直接アクセスすると、その語で検索した状態で開きます。
検索を無効にする
features: {
search: false,
},astro-paper.config.ts
false にすると、ナビゲーションから検索リンクが消え、/search/ へ直接アクセスしても404ページが表示されます。
日本語の検索について
Pagefindは多言語に対応していますが、日本語のように単語の区切りが空白でない言語では、英語ほど素直に一致しないことがあります。実際の記事で検索を試して、期待どおりに見つかるか確かめてください。言語はページの lang 属性から判定されるので、site.lang を "ja" にしておくのが前提です。
RSSフィード
/rss.xml で配信されます。RSSは、読者が購読ツールに登録しておくと新着記事が届く仕組みです。
生成しているのは src/pages/rss.xml.ts です。
return rss({
title: config.site.title,
description: config.site.description,
site: config.site.url,
items: sortedPosts.map(({ data, id, filePath }) => ({
link: getPostUrl(id, filePath, config.site.lang),
title: data.title,
description: data.description,
pubDate: new Date(data.modDatetime ?? data.pubDatetime),
})),
});src/pages/rss.xml.ts
押さえておくのは次の3つです。
- 記事は
getSortedPostsを通っているので、下書きと未来の予約記事は含まれません。 - 本文は含まれず、
descriptionだけが配信されます。読者はリンクをたどって本文を読みます。 - 日付は
modDatetimeが優先されます。記事を更新すると、購読ツール上で新着として再表示される場合があります。
description は一覧にもSEOにもRSSにも使われます。記事の中身を正確に、短くまとめておいてください。
1件のフィードに何が入るのかを、注意点とあわせて示します。
なお、RSSの存在はすべてのページの <head> から自動で通知されています。
<link rel="alternate" type="application/rss+xml" title={site.title} href={...} />src/layouts/Layout.astro
これにより、購読ツールがサイトのURLだけでフィードを見つけられます。
サイトマップ
サイトマップは、サイト内のURL一覧を検索エンジンへ伝えるファイルです。@astrojs/sitemap インテグレーションが生成します。
integrations: [
mdx(),
sitemap({
filter: page =>
config.features?.showArchives !== false || !page.endsWith("/archives/"),
}),
],astro.config.ts
filter は、サイトマップに含めるURLを選ぶ関数です。ここではアーカイブ機能を無効にしている場合に /archives/ を外しています。非公開にしたページを検索エンジンへ伝えないための処理です。
生成先は /sitemap-index.xml で、<head> からも参照されています。
<link rel="sitemap" href={getAssetPath("sitemap-index.xml")} />src/layouts/Layout.astro
サイトマップが正しく作られるには、
astro.config.tsのsite(=astro-paper.config.tsのsite.url)が設定されている必要があります。URLが誤っていると、存在しないアドレスの一覧ができてしまいます。
robots.txt
robots.txt は、検索エンジンのクローラーに対する指示を書くファイルです。src/pages/robots.txt.ts が生成します。
const getRobotsTxt = (sitemapURL: URL) => `
User-agent: *
Allow: /
Sitemap: ${sitemapURL.href}
`;src/pages/robots.txt.ts
すべてのクローラーに全ページの巡回を許可して、サイトマップの場所を伝える。それだけの内容です。サイトマップのURLは site 設定から組み立てられるので、手で書き換える必要はありません。
特定のページを巡回対象から外したい場合は、このファイルへ Disallow: の行を足します。
運用上の注意点
ビルドのタイミング
検索索引もRSSもサイトマップも、すべてビルド時に作られる静的なファイルです。記事を追加してGitに反映しただけでは更新されません。デプロイのたびにビルドが走る構成にしてください。
検索の確認手順
検索の動作を確かめたいときは、次の順で実行します。
pnpm build
pnpm preview
pnpm preview で表示されたURLの /search/ を開けば、本番と同じ状態で検索を試せます。
開発サーバーだけの場合と比べると、なぜこの手順が必要なのかがはっきりします。
索引ファイルとバージョン管理
public/pagefind/ はビルドで作られる生成物です。テンプレートの .gitignore にも登録されているため、そのままにしておけば問題ありません。
要点
- Pagefindはビルド後のHTMLから索引を作るため、
pnpm devだけでは検索が動かず、必ず一度pnpm buildが必要である。 - 索引に入るのは
data-pagefind-bodyが付いた記事本文だけで、一覧ページや前後リンクは除外されている。 - RSSには本文ではなく
descriptionが配信され、日付はmodDatetimeが優先される。 - サイトマップは
site.urlを基準に生成され、アーカイブを無効にした場合はそのURLが除外される。 robots.txtはルートとして生成され、サイトマップの場所を自動で含む。
参考資料
- Pagefind 公式サイト — 索引の生成と
data-pagefind-*属性 - テンプレート同梱ソース
src/pages/search.astro— 検索UIの初期化と検索語のURL保持 - テンプレート同梱ソース
src/pages/rss.xml.ts/robots.txt.ts— フィードとクローラー向け指示の生成 - テンプレート同梱ソース
astro.config.ts— サイトマップのfilter設定 - @astrojs/rss ドキュメント — RSS生成の仕様
- @astrojs/sitemap ドキュメント — サイトマップの設定項目
- MDN: requestIdleCallback — 遅延読み込みの仕組み
シリーズ目次 前章: 08. AstroPaperの配色テーマをカスタマイズする 次章: 10. AstroPaperでOG画像の自動生成とSEO