Skip to content
Cloud AI エンジニア入門ガイド
Go back

09. AstroPaperの検索・RSS・サイトマップ

この章の全体像として、サイト内検索、RSS、サイトマップ、robots.txtの4つを番号順に並べ、読者が記事へたどり着く経路を整えられるようになることを示した図

シリーズ目次 前章: 08. AstroPaperの配色テーマをカスタマイズする 次章: 10. AstroPaperでOG画像の自動生成とSEO

Table of contents

Open Table of contents

この章のねらい

AstroPaperには、サイト内検索とRSSフィード、サイトマップ、robots.txt が最初から入っています。どれも、読者や検索エンジンが記事にたどり着くための入口です。それぞれがいつ作られてどう使われるのかを見ていきます。

ビルド時に索引とフィードが生成され、読者のアクセス時に利用されるまでの流れを示した図

サイト内検索(Pagefind)

静的サイトで全文検索ができる理由

全文検索には普通、検索用のサーバーかデータベースが要ります。ところがAstroPaperは静的サイトで、配信されるのはHTMLファイルだけです。

Pagefind はこの制約をこう解きました。

  1. ビルドが終わった後のHTMLファイルを読む
  2. そこから検索用の索引(インデックス)ファイルを作っておく
  3. 読者が検索したとき、ブラウザが必要な索引だけを取得して絞り込む

索引は語ごとに細かく分割されているので、記事が増えてもブラウザが読み込むデータ量はあまり増えません。サーバーなしで、実用的な速度の全文検索が成立する。これがPagefindです。

索引が作られるタイミング

索引はビルドの後半で作られます。package.jsonbuild を再掲します。

{
  "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

隣の記事のタイトルが検索結果に紛れ込まないようにするための配慮です。

索引に入る範囲と入らない範囲を並べると、設計の意図が見えてきます。

data-pagefind-bodyが付いた記事本文だけが索引に入り、記事一覧・タグ・アーカイブ・前後リンクは索引から外れることを左右に並べて示した図

検索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つです。

description は一覧にもSEOにもRSSにも使われます。記事の中身を正確に、短くまとめておいてください。

1件のフィードに何が入るのかを、注意点とあわせて示します。

rss.xmlの1件に含まれる項目と本文が含まれないこと、下書きの除外・descriptionのみの配信・modDatetime優先という3つの注意点を並べた図

なお、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.tssite(=astro-paper.config.tssite.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 にも登録されているため、そのままにしておけば問題ありません。

要点

参考資料


シリーズ目次 前章: 08. AstroPaperの配色テーマをカスタマイズする 次章: 10. AstroPaperでOG画像の自動生成とSEO


Share this post:

Previous Post
10. AstroPaperでOG画像の自動生成とSEO
Next Post
08. AstroPaperの配色テーマをカスタマイズする