VitePressブログに施したSEO対策まとめ
公開日: 2026-03-01
VitePressで構築した当ブログのSEO評価を確認したところ、7つの改善項目が見つかりました。本記事では、それぞれの対策内容と実装方法をまとめます。
変更ファイルはたった3つで、ほとんどが config.js への追記だけで完結します。なお、以下のコード例ではサイト名・著者名などをプレースホルダとしています。実際の値はご自身のサイトに合わせて置き換えてください。
| # | 対策 | 変更ファイル |
|---|---|---|
| 1 | HTML言語属性の設定 | config.js |
| 2 | サイトマップの自動生成 | config.js |
| 3 | robots.txt の作成 | docs/public/robots.txt(新規) |
| 4 | OGPタグの動的生成 | config.js |
| 5 | Twitterカードタグの動的生成 | config.js |
| 6 | canonical URL + JSON-LD構造化データ | config.js |
| 7 | RSSフィードの生成 | config.js + package.json |
1. HTML言語属性の設定
HTMLの <html> タグにはページの言語を示す lang 属性が必要です。これが未設定だと、検索エンジンがページの言語を正しく判定できません。
VitePressでは defineConfig に lang を指定するだけで反映されます。
export default defineConfig({
lang: 'ja',
})ビルド後のHTMLに <html lang="ja"> が出力されます。
2. サイトマップの自動生成
サイトマップは、検索エンジンのクローラーにサイト内のページ一覧を伝えるXMLファイルです。VitePress v1.x には組み込みのサイトマップ生成機能があるため、hostname を指定するだけで sitemap.xml が自動生成されます。
export default defineConfig({
sitemap: {
hostname: 'https://garookie.com'
},
})3. robots.txt の作成
robots.txt はクローラーに対して、サイト内のどのページをクロールしてよいかを指示するファイルです。サイトマップの場所もここで明示できます。
docs/public/robots.txt に配置すると、ビルド時にそのまま出力ディレクトリへコピーされます。
User-agent: *
Allow: /
Sitemap: https://garookie.com/sitemap.xml4. OGPタグの動的生成
OGP(Open Graph Protocol)タグを設定すると、SNSやメッセージアプリでURLを共有した際にタイトル・説明文・サイト名などがリッチに表示されます。
VitePressの transformHead フックを使うと、ページごとのfrontmatterから動的にmetaタグを生成できます。
export default defineConfig({
transformHead({ pageData }) {
const head = []
// relativePathからページURLを組み立てる
const pagePath = pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2')
const pageUrl = `${hostname}/${pagePath}`
const title = pageData.frontmatter.title || 'サイト名'
const description = pageData.frontmatter.description || 'サイト説明'
const isPost = pageData.relativePath.startsWith('posts/') && pageData.frontmatter.date
head.push(['meta', { property: 'og:type', content: isPost ? 'article' : 'website' }])
head.push(['meta', { property: 'og:title', content: title }])
head.push(['meta', { property: 'og:description', content: description }])
head.push(['meta', { property: 'og:url', content: pageUrl }])
head.push(['meta', { property: 'og:site_name', content: 'サイト名' }])
head.push(['meta', { property: 'og:locale', content: 'ja_JP' }])
return head
}
})ポイントは、記事ページでは og:type を article に、それ以外では website にしている点です。
5. Twitterカードタグの動的生成
Twitterカードタグを設定すると、X(旧Twitter)でURLを共有した際にカード形式で表示されます。OGPと同じく transformHead 内で生成します。
head.push(['meta', { name: 'twitter:card', content: 'summary' }])
head.push(['meta', { name: 'twitter:title', content: title }])
head.push(['meta', { name: 'twitter:description', content: description }])6. canonical URL + JSON-LD構造化データ
canonical URL
canonical URLは「このページの正規URLはこれです」と検索エンジンに明示するためのタグです。重複コンテンツの評価分散を防ぎます。
以下のコードはすべて上記セクション4の transformHead 内での処理です。pageUrl の組み立てについてはセクション4を参照してください。
head.push(['link', { rel: 'canonical', href: pageUrl }])JSON-LD構造化データ
JSON-LDは検索エンジンにページの意味(記事なのか、サイトなのか等)を構造化データとして伝える仕組みです。Googleの検索結果でリッチリザルトとして表示される可能性が高まります。
記事ページには BlogPosting、それ以外には WebSite スキーマを設定しました。
// 記事ページの場合
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: title,
description,
url: pageUrl,
datePublished: pageData.frontmatter.date,
author: { '@type': 'Person', name: '著者名' },
publisher: { '@type': 'Organization', name: 'サイト名' }
}
head.push(['script', { type: 'application/ld+json' }, JSON.stringify(jsonLd)])7. RSSフィードの生成
RSSフィードを配信すると、フィードリーダーの利用者が新着記事を自動で受け取れるようになります。また、一部の検索エンジンもRSSフィードを参照します。
まず feed パッケージをインストールします。
npm install -D feedVitePressの buildEnd フックで、ビルド完了時に feed.xml を生成します。
import { createContentLoader } from 'vitepress'
import { writeFileSync } from 'fs'
import path from 'path'
import { Feed } from 'feed'
export default defineConfig({
// headにRSS自動検出リンクを追加
head: [
['link', { rel: 'alternate', type: 'application/rss+xml', title: 'サイト名', href: '/feed.xml' }]
],
async buildEnd(siteConfig) {
const feed = new Feed({
title: 'サイト名',
description: 'サイト説明',
id: hostname,
link: hostname,
language: 'ja',
})
const posts = await createContentLoader('posts/*.md', {
excerpt: true,
render: true
}).load()
posts
.filter(p => p.frontmatter.date)
.sort((a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date))
.forEach(post => {
feed.addItem({
title: post.frontmatter.title,
id: `${hostname}${post.url}`,
link: `${hostname}${post.url}`,
description: post.frontmatter.description || '',
date: new Date(post.frontmatter.date)
})
})
writeFileSync(path.join(siteConfig.outDir, 'feed.xml'), feed.rss2())
}
})head に <link rel="alternate"> を追加することで、ブラウザやフィードリーダーがRSSフィードを自動検出できるようにもなります。
まとめ
今回の対策は、変更ファイル3つ(config.js / robots.txt / package.json)だけで完結しました。VitePressは sitemap の組み込み機能や transformHead / buildEnd といったフックが用意されているため、プラグインを追加することなくSEO対策を実装できるのが良いところです。
| 対策 | 効果 |
|---|---|
| lang属性 | 検索エンジンが言語を正しく認識 |
| サイトマップ | クローラーが全ページを効率的に巡回 |
| robots.txt | クロールの許可とサイトマップの所在を明示 |
| OGPタグ | SNSシェア時にリッチ表示 |
| Twitterカード | Xでのシェア時にカード表示 |
| canonical + JSON-LD | 重複防止 + リッチリザルト対応 |
| RSSフィード | フィードリーダーでの新着記事配信 |