ブログをアップデートしました

Author: lcyou , 8 min ,

Published: 2026-02-22 / Last modified: 2026-04-06

Astroで個人ブログを立ち上げて記事も書き始めたので、そろそろSEO対策をしっかりやろう!と重い腰を上げて実装しました。 TwitterやDiscordでシェアした時にいい感じのプレビューが表示されるようにしたり、検索エンジンに登録されやすくしたりと、ブログとして最低限必要な機能を整えた記録です。

モチベーション

ブログ記事を書いて、TwitterやDiscordでシェアした時のことです。 リンクを貼っただけだと、味気ないテキストのみの表示になってしまいました。 他の人のブログ記事だと、タイトルや説明、画像付きのかっこいいプレビューが表示されるのに!

調べてみると、これはOGP(Open Graph Protocol)というメタタグの設定が必要だとわかりました。 せっかくブログを作ったのだから、シェアした時の見栄えも良くしたいです。

それに加えて、検索エンジンに登録してもらうためのサイトマップや、RSSリーダー対応も必要だと感じました。 ブログとして最低限の機能を整えるため、これらをまとめて実装することにしました。

実装したもの

今回実装したSEO関連の機能は以下の通りです。

  1. OGP(Open Graph Protocol)タグの実装
  2. 動的OG画像の自動生成(Satoriを使用)
  3. サイトマップの自動生成
  4. RSSフィードの実装

Astroには公式パッケージが充実しているので、思ったより簡単に実装できました! それぞれ見ていきます。

OGPタグの実装(astro-seo)

OGPタグを手動で書くのは大変なので、astro-seoというパッケージを使いました。

サイト全体の基本情報をsrc/data/seo.tsにまとめ、メタタグを追加するだけでした。

export const siteConfig = {
  title: "lCyou's Blog",
  description: "技術的なことや本の感想など、いろいろ書いています。",
  url: "https://blog.lcyou.me",
  author: "lcyou",
  twitter: "@lcyou",
  image: "/favicon.svg",
  locale: "ja_JP",
};
<SEO
  title={pageTitle ? `${pageTitle} | ${siteConfig.title}` : siteConfig.title}
  description={description}
  canonical={pageUrl}
  openGraph={{
    basic: {
      title: pageTitle || siteConfig.title,
      type: article ? 'article' : 'website',
      image: ogImageUrl,
      url: pageUrl,
    },
    optional: {
      description: description,
      locale: siteConfig.locale,
      siteName: siteConfig.title,
    },
    image: {
      alt: ogImageAlt || pageTitle || siteConfig.title,
      width: 1200,
      height: 630,
    },
  }}
  twitter={{
    card: 'summary_large_image',
    site: siteConfig.twitter,
    creator: siteConfig.twitter,
  }}
/>

これで、ページごとに適切なOGPタグが自動で設定されるようになりました! Twitter Cardsにも対応しているので、Twitterでシェアした時もいい感じに表示されます。

動的OG画像の自動生成(Satori)

OGPタグの実装で一つ問題がありました。 それは、記事ごとにOG画像(プレビュー画像)を用意するのが面倒ということです。

そこで、記事のタイトルや説明文から自動で画像を生成する仕組みを導入しました。

使用したのはSatoriというライブラリです。 SatoriはReact要素をSVG画像に変換してくれる優れものです。

実装はsrc/pages/og/[...slug].svg.tsに配置しました。 動的ルーティングを使って、その記事専用のOG画像が生成しています。

タイトル、説明文、タグが入った画像が自動で作られるので、画像作成の手間がゼロになりました。

サイトマップの自動生成

サイトマップは検索エンジンにサイトの構造を伝えるためのXMLファイルです。 Astroには公式の@astrojs/sitemapパッケージがあるので、これを使いました。

astro.config.mjsに以下を追加するだけです。

import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: "https://blog.lcyou.me",
  integrations: [sitemap()],
});

たったこれだけで、ビルド時に自動でsitemap-index.xmlsitemap-*.xmlが生成されます。 トップページ、記事ページ、タグページなど、全てのページが自動的にサイトマップに含まれます。

RSSフィードの実装

ブログといえばRSSフィードですよね() RSSリーダーで購読してくれる人のために、RSSフィードも実装しました。

src/pages/rss.xml.jsを作成して、以下のように実装しました。

import rss, { pagesGlobToRssItems } from '@astrojs/rss';

export async function GET(context) {
  return rss({
    title: "lCyou's Blog",
    description: 'lcyouがなんでも記事に書き起こす場所',
    site: 'https://blog.lcyou.me',
    items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')),
    customData: `<language>ja-jp</language>`,
  });
}

pagesGlobToRssItemsが全てのMarkdownファイルを自動で検出してくれるので、記事を書くだけで自動的にRSSフィードに追加されます。 これもAstroの公式パッケージ@astrojs/rssのおかげで、あっという間に実装できました。

ついでに機能追加してみたものたち

ついでに以下機能も追加してみました。

記事の目次はAstroのMarkdownページのPropsからheadingsというものが取れるのでよしなに表示させてます。

interface Heading {
  depth: number;
  slug: string;
  text: string;
}

interface Props {
  headings: Heading[];
}

const { headings } = Astro.props;
const tocHeadings = headings.filter((h) => h.depth >= 2 && h.depth <= 4);

記事の全文検索は、pagefindを使いました。 DB登録とかなしに検索してきます。中身はこれから読みます。()

まとめ

今回、AstroブログにSEO対策として以下を実装しました。

Astroの公式パッケージが充実しているおかげで、思っていたよりもずっと簡単に実装できました。 特にSatoriを使った動的OG画像生成は、記事を書くだけで自動的に画像が生成されるので、かなり便利です!

これでブログとしての基本機能が一通り揃いました。 (が、なかなか検索には引っ掛からなそうですが、、、) 次はアクセス解析とか、もっと細かいSEO対策にも挑戦してみたいです。