SEO最適化:useHead + useSeoMeta
CharlieのMegaShopには100万商品ページがありますが, Googleにインデックスされているのはわずか2,000ページです。Aliceが商品名で検索してもMegaShopのページが見つかりません。Bobが確認すると, 商品ページにはタイトル, メタディスクリプション, Open Graphタグ, 構造化データがすべて欠けていました。Nuxt 3のSEOツールチェーンがこれらすべての問題を解決できます。
1. 学ぶ内容
- useHead():title, meta, link, script, styleタグの動的管理
- useSeoMeta():構造化SEOメタデータ (OG/Twitter/description)
- Nuxt 3の組み込みSEOデフォルトとオーバーライドメカニズム
- サイトマップとrobots.txt:@nuxtjs/sitemapモジュール
- MegaShop商品詳細ページの動的SEO + JSON-LD + 自動サイトマップ生成
2. アーキテクトのある本当の話
(1) 課題:100万ページのうちGoogleにインデックスされているのはわずか2,000
CharlieがGoogle Search ConsoleでMegaShopを確認すると, 100万商品ページのうちわずか2,000しかインデックスされていませんでした。Bobの分析によると, すべての商品ページのタイトルが「MegaShop」で, メタディスクリプションは空, Open Graphタグもないため, SNSでシェアしてもサイト名しか表示されず, 商品情報が表示されません。
(2) Nuxt SEOツールチェーンの解決策
Nuxt 3のuseHeadとuseSeoMetaにより, 各商品ページに独自のSEOメタデータを持たせることができます:
TYPESCRIPT
// pages/products/[id].vue
useSeoMeta({
title: product.value?.name,
ogTitle: product.value?.name,
description: `Buy ${product.value?.name} for $${product.value?.price} USD`,
ogImage: product.value?.image
})
(3) 結果:Googleインデックス率が40倍に急増
3か月後, Googleのインデックスは2,000から800,000に急増し, オーガニック検索トラフィックは340%増加しました。
3. SEOツールチェーンアーキテクチャ
(1) Nuxt 3 SEOツールチェーンの概要
graph TB
A[Nuxt SEOツールキット] --> B[useHead]
A --> C[useSeoMeta]
A --> D[JSON-LD]
A --> E["@nuxtjs/sitemap"]
A --> F[robots.txt]
B --> B1[title / meta / link]
C --> C1[OG / Twitter Card]
D --> D1[Product / Breadcrumb]
E --> E1[動的URL生成]
F --> F1[クローラーアクセス制御]
4. useHeadの動的管理
(1) useHeadで管理できるもの
| タグ種別 | 属性 | SEOへの影響 |
|---|---|---|
| title | ページタイトル | 🔴 高 (ランキングシグナル) |
| meta name="description" | ページ説明 | 🔴 高 (クリック率) |
| meta property="og:*" | Open Graph | 🟡 中 (ソーシャルシェア) |
| meta name="twitter:*" | Twitter Card | 🟡 中 (ソーシャルシェア) |
| link rel="canonical" | 正規URL | 🔴 高 (重複排除) |
| link rel="alternate" | 多言語URL | 🟡 中 (i18n SEO) |
| script type="application/ld+json" | JSON-LD | 🟡 中 (リッチスニペット) |
(1) ▶ サンプル:useHeadの基本使用
TYPESCRIPT
// 任意のコンポーネントまたはページで
useHead({
title: 'Premium Headphones - MegaShop',
meta: [
{ name: 'description', content: 'Buy Premium Headphones for $299.99 USD. Free shipping.' },
{ name: 'keywords', content: 'headphones, wireless, premium, audio' }
],
link: [
{ rel: 'canonical', href: 'https://megashop.com/products/123' }
]
})
出力:
TEXT
// 実行成功
(2) ▶ サンプル:動的タイトル (computed, リアクティブ)
VUE
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// 商品読み込み時に更新される動的タイトル
useHead({
title: computed(() => product.value
? `${product.value.name} - MegaShop`
: 'Loading... - MegaShop'
)
})
</script>
出力:
TEXT
// 実行成功
(3) ▶ サンプル:グローバルデフォルト設定
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
title: 'MegaShop - Premium E-Commerce',
titleTemplate: '%s | MegaShop',
meta: [
{ name: 'description', content: 'Over 1 million products shipped worldwide' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ charset: 'utf-8' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}
}
})
出力:
TEXT
// 実行成功
5. useSeoMeta構造化SEO
(1) useSeoMetaとuseHeadの比較
| 項目 | useHead | useSeoMeta |
|---|---|---|
| 対象 | 汎用Head管理 | SEO専用ショートカット |
| APIスタイル | 配列オブジェクト | キー・バリュー |
| OG/Twitter | 手動metaタグ入力が必要 | 1行で完了 |
| 型安全性 | ⚠️ ドキュメント確認が必要 | ✅ 完全な型ヒント |
| 重複排除 | ⚠️ 手動管理 | ✅ 自動重複排除 |
(1) ▶ サンプル:商品詳細ページSEO
VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// 構造化SEOメタデータ - 型安全
useSeoMeta({
title: () => `${product.value?.name} - Buy Online`,
ogTitle: () => `${product.value?.name} - MegaShop`,
description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. ${product.value?.reviewCount} reviews, ${product.value?.rating} stars. Free shipping worldwide.`,
ogDescription: () => `Premium ${product.value?.name} - $${product.value?.price} USD`,
ogImage: () => product.value?.image || '/images/og-default.jpg',
ogUrl: () => `https://megashop.com/products/${route.params.id}`,
ogType: 'product',
twitterCard: 'summary_large_image',
twitterTitle: () => `${product.value?.name} - MegaShop`,
twitterImage: () => product.value?.image || '/images/og-default.jpg'
})
</script>
出力:
TEXT
// 実行成功
(2) ▶ サンプル:ホームページSEO
TYPESCRIPT
// pages/index.vue
useSeoMeta({
title: 'MegaShop - Over 1 Million Products',
ogTitle: 'MegaShop - Premium E-Commerce Platform',
description: 'Shop over 1 million products with free worldwide shipping. Electronics, fashion, home & garden at the best prices.',
ogDescription: 'Discover 1 million+ products on MegaShop. Free shipping on orders over $50 USD.',
ogImage: '/images/og-homepage.jpg',
ogUrl: 'https://megashop.com',
ogType: 'website'
})
出力:
TEXT
// 実行成功
6. JSON-LD構造化データ
(1) 構造化データが検索結果に与える影響
| データ種別 | Googleリッチスニペット結果 | MegaShopでの対応 |
|---|---|---|
| Product | 価格/評価/在庫 | ✅ 商品詳細ページ |
| BreadcrumbList | パンくずナビゲーション | ✅ 全ページ |
| Organization | 会社情報 | ✅ ホーム |
| Website | サイト検索ボックス | ✅ ホーム |
| Review | レビュー概要 | ✅ 商品ページ |
(1) ▶ サンプル:商品JSON-LD
VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// Googleリッチ結果向けJSON-LD構造化データ
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: computed(() => JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value?.name,
image: product.value?.image,
description: product.value?.description,
sku: `MEGA-${product.value?.id}`,
offers: {
'@type': 'Offer',
url: `https://megashop.com/products/${route.params.id}`,
priceCurrency: 'USD',
price: product.value?.price,
availability: product.value?.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock'
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: product.value?.rating,
reviewCount: product.value?.reviewCount
}
}))
}
]
})
</script>
出力:
TEXT
// 実行成功
(2) ▶ サンプル:パンくずJSON-LD
TYPESCRIPT
// composables/useBreadcrumbLd.ts
export function useBreadcrumbLd(items: { name: string; url: string }[]) {
useHead({
script: [{
type: 'application/ld+json',
innerHTML: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url
}))
})
}]
})
}
// ページでの使用
useBreadcrumbLd([
{ name: 'Home', url: 'https://megashop.com' },
{ name: 'Products', url: 'https://megashop.com/products' },
{ name: 'Premium Headphones', url: 'https://megashop.com/products/123' }
])
出力:
TEXT
// 実行成功
7. サイトマップとrobots.txt
(1) ▶ サンプル:@nuxtjs/sitemapのインストール
BASH
npm install @nuxtjs/sitemap
出力:
TEXT
# コマンド実行成功
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/sitemap'],
sitemap: {
hostname: 'https://megashop.com',
gzip: true,
routes: async () => {
// 100万商品の動的ルート
const products = await $fetch('/api/products/all-ids')
return products.map((id: number) => ({
loc: `/products/${id}`,
lastmod: new Date().toISOString(),
changefreq: 'daily',
priority: 0.8
}))
},
defaults: {
changefreq: 'weekly',
priority: 0.5
}
}
})
(2) ▶ サンプル:robots.txt
TEXT
// public/robots.txt
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Disallow: /profile/
Sitemap: https://megashop.com/sitemap.xml
出力:
TEXT
実行成功
(1) サイトマップ戦略の比較
| 戦略 | メリット | デメリット | 適用規模 |
|---|---|---|---|
| 単一ファイルsitemap.xml | シンプル | ≤ 50,000 URL | 小規模サイト |
| サイトマップインデックス | 数百万URLに対応 | 分割が必要 | MegaShop |
| 動的ルート生成 | 新ページを自動反映 | ビルド時クエリが必要 | 商品ページ |
| モジュール自動生成 | ゼロ設定 | 制限あり | 中小規模サイト |
8. 総合例:MegaShop商品ページの完全SEOガイド
VUE
<!-- pages/products/[id].vue -->
<template>
<div v-if="product" class="product-page">
<h1>{{ product.name }}</h1>
<p class="price">${{ product.price }} USD</p>
<p>{{ product.reviewCount }} reviews · {{ product.rating }} stars</p>
</div>
</template>
<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
const productUrl = `${config.public.siteUrl}/products/${route.params.id}`
// SEO Meta
useSeoMeta({
title: () => `${product.value?.name} - MegaShop`,
ogTitle: () => product.value?.name,
description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. Free shipping. ${product.value?.reviewCount} reviews.`,
ogDescription: () => `${product.value?.name} - $${product.value?.price} USD on MegaShop`,
ogImage: () => product.value?.image,
ogUrl: () => productUrl,
ogType: 'product',
twitterCard: 'summary_large_image'
})
// 正規URL
useHead({
link: [{ rel: 'canonical', href: productUrl }]
})
// JSON-LD
useHead({
script: [{
type: 'application/ld+json',
innerHTML: computed(() => JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value?.name,
image: product.value?.image,
offers: {
'@type': 'Offer',
priceCurrency: 'USD',
price: product.value?.price,
availability: product.value?.inStock ? 'InStock' : 'OutOfStock'
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: product.value?.rating,
reviewCount: product.value?.reviewCount
}
}))
}]
})
</script>
❓ よくある質問
Q
useSeoMetaとuseHeadは一緒に使えますか?A はい, 同じ
Headインスタンスを操作します。useSeoMetaはSEOタグを管理し, useHeadは他のタグ (canonical/JSON-LD/style)を管理します。Q 100万商品ページのサイトマップはどう扱えばよいですか?
A サイトマップインデックスを使用して複数のサブサイトマップに分割します (各50,000 URL以内)。@nuxtjs/sitemapモジュールは自動分割をサポートしています。
Q JSON-LDの
innerHTMLはXSSリスクがありますか?A Nuxt 3は
scriptタグのinnerHTMLにセキュリティ対策を適用します。ただし, JSON.stringifyを使用し, 動的データをエスケープしてインジェクションを防ぐのが最善です。Q CSRモードでSEOメタデータは機能しますか?
A 検索エンジンのクローラーはCSRでレンダリングされたmetaタグをサポートしていません。SEOが必要なページではSSR, ISR, またはSSGを使用する必要があります。CSRページのmetaタグはクライアント側ハイドレーション後にのみ表示されます。
Q titleTemplateの使い方は?
A nuxt.config.tsで
titleTemplate: '%s | MegaShop'を設定します。ページのuseHeadではtitleの内容だけを設定すれば, テンプレートが自動的に構築されます。Q ogImage画像にサイズ要件はありますか?
A Facebookは1200x630px, Twitterは1200x600px (summary_large_image)を推奨しています。小さすぎる画像は表示されない場合があります。
📖 まとめ
useHeadはHeadタグの汎用マネージャー,useSeoMetaはSEOメタデータに特化し, より高い型安全性を提供- 動的SEO:computed, リアクティブなタイトルと説明。各商品ページに固有のメタデータ
- JSON-LD構造化データによりGoogleはリッチスニペット (価格, 評価, 在庫)を表示
- @nuxtjs/sitemapがサイトマップを自動生成し, 数百万URLのサイトマップインデックスに対応
- robots.txtがクローラーのアクセス範囲を制御し, admin/api/profileパスをブロック
📝 練習問題
- 基本問題 (難易度:⭐):
useHeadを使ってホームページのタイトルとメタディスクリプションを設定し, ソースコードを表示して確認してください。 - 応用問題 (難易度:⭐⭐):
useSeoMetaを使って商品詳細ページにOGとTwitter Cardメタデータを完全に設定し, Facebook Sharing Debuggerで検証してください。 - チャレンジ (難易度:⭐⭐⭐):商品ページのJSON-LD自動生成, パンくずJSON-LD, サイトマップを実装し, Google Rich Results Testで構造化データを検証してください。
---|



