Astroブログの下書きを、一覧・RSS・サイトマップからも除外する
このブログは、AIと下書きを作り、ローカルで読んでから公開している。下書きは手元で確認したい。でも、本番には出したくない。
そのために記事へ付けているのが、draft: trueだ。今回整理したのは、この値を記事ページだけでなく、一覧やRSSなどの出力にも反映する処理だった。

画像:Astro公式サイトの共有用画像。
まず、記事が出ていく場所を確認した
このサイトはAstro 5系とMDXを使っている。記事をコレクションから読み、ビルド時にページを生成する構成だ。以下はこのリポジトリの実装についての話で、最新のAstroへの移行手順ではない。
記事は、本文ページ以外にも使われている。
| 出力先 | 今回確認したこと |
|---|---|
| 記事ページ | 下書きのURLに対応するHTMLを生成しない |
| TOP・記事一覧・関連記事 | 下書きを並べない |
| タグ | 下書きだけで使うタグのページを生成しない |
| RSS | 下書きのタイトルや説明を配信しない |
| 自動生成OGP | 下書きタイトル入りの画像を生成しない |
| サイトマップ・サイト内検索 | ビルド後の出力に下書きを含めない |
TOPからリンクを消すだけだと、直接URLを開けたり、別の出力にタイトルが残ったりする可能性がある。記事データを使う場所をたどって、公開条件が揃っているかを確認した。
開発時と本番で、取り出す記事を変える
記事一覧やページ生成で使う関数には、次の条件を置いている。
const nonDraft = all.filter(
w => import.meta.env.DEV || !w.data.draft,
);開発時は全記事を返し、本番ではdraftが有効な記事を除く。記事ページのgetStaticPaths()も、この条件を通した記事からURLを生成する。
この実装では、draft: falseとdraftの未指定を公開扱いにしている。自分一人の運用として使っているが、未指定なら非公開にしたいサイトでは、条件とスキーマの既定値を変える必要がある。
記事のデータ定義はsrc/content.config.tsにある。公開日やタイトルの型に加え、登録されていないタグを入力した場合も検出するようにしている。下書きかどうかと、記事データが正しいかどうかは別々に確認する。
RSSとOGPも、それぞれ確認する
RSSは別の処理でコレクションを読み込んでいる。こちらには、開発時でも下書きを配信しない条件を置いた。
const posts = (await getCollection('notes'))
.filter(post => !post.data.draft)
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime());タイトルからOGP画像を作るエンドポイントにも、公開条件が必要だった。本文を除外しても、画像の生成対象に下書きが残っていたら、別の出口が開いてしまう。
タグ一覧も、全記事ではなく、表示対象の記事からタグを集めている。本番に下書きしかないタグは、タグ一覧にも独立したページにも出さない。
このように、現在は記事取得、RSS、OGPで条件をそれぞれ持っている。出力先を追加するときに条件を忘れないことが、今の構成の注意点だ。今後整理するなら、公開記事を取得する処理と、開発用に下書きも取得する処理を明示的に分けたい。
開発画面にはnoindexを付ける
ローカルで表示する下書きにはnoindexを付けている。ただし、これは閲覧を制限する機能ではない。
今回の本番向け対策は、下書きページをビルド対象から外すこと。開発サーバーを外部に公開しないことも、別に必要になる。
また、public/に置いたファイルは、そのまま配信される。この処理で下書き記事を除外しても、そこに置いた専用画像や添付資料までは非公開にならない。秘密の情報を置くための仕組みとしては使えない。
画面と、ビルドの両方で確認した
SEO周りを整備したときには、一時的な下書きと、その下書きだけで使うタグを用意して、本番ビルドを確認した。
記事ページ、一覧、RSS、サイトマップ、自動生成OGP、タグページに含まれないことを確認し、確認用の記事は取り除いた。サイト内検索は本番出力をPagefindで索引化するため、生成するHTMLの範囲も確認対象にした。
この記事を含む下書きでも、開発時に読めることと、本番出力に含まれないことを確認した。
「下書き」という一つの状態でも、その情報を使う場所は複数ある。新しい記事機能を足したときには、どこへ出力されるのかまで追う。このブログでは、その確認を公開前の作業にしている。
実装と確認はCodexと一緒に進めた。この記事の条件式は、このサイトの実装から抜粋している。