VueのSEO

素の Vite + Vue 3 スキャフォールドではコンテンツが生の HTML に入らない CSR が標準です。Vue アプリをクロール、インデックス可能にするためのルーターモード、@unhead/vue、vite-ssg のプリレンダリング、Nuxt の SSR/SSG、ハイドレーション、Core Web Vitals を解説します。

初回公開:2026年6月26日 · 最終更新:2026年8月22日 · Advanced
言語

素の Vite + Vue 3 アプリは標準では CSR で、空に近い HTML シェルを配信し、ブラウザでページを構築します。Google はレンダリングできますが遅延があり、非同期データを見落とす可能性があります。Bing やソーシャルスクレイパーは JavaScript を実行できないことも少なくありません。Vue Router の history モードを使い、@unhead/vue で <head> を管理し、vite-ssg のプリレンダリング、SSR、または Nuxt の SSG でコンテンツを HTML に含めます。動的レンダリングは非推奨です。

TL;DR — 素の Vite + Vue 3 はデフォルトで CSR のため、コンテンツは生の HTML に含まれません。Google は最新の Chromium WRS で後からレンダリングしますが、処理はキューに入り、onMounted で取得する非同期データは見落とされる可能性があります。Bing やソーシャルスクレイパーは JavaScript を実行しないことも少なくありません。必須事項は、Vue Router の createWebHistory()(ハッシュモードは「SEO に悪影響」)、<head> を管理する @unhead/vue / useSeoMeta()、そしてコンテンツを HTML に入れるレンダリング戦略です。内容が安定したサイトには vite-ssg によるプリレンダリング、完全な SSR/SSG には Nuxt を使います。動的レンダリングは 非推奨で、prerender-spa-plugin はレガシーです。ハイドレーションの不一致と CSR バンドルによる LCP 悪化にも注意してください。一般的な仕組みは JavaScript SEO で解説しています。

デフォルトのVite + Vueスキャフォールドはクライアントサイドレンダリングされる

素の npm create vue@latest アプリ(Vite + Vue)は、ほぼ空の HTML シェルと JavaScript バンドルを出荷します。ブラウザはそのバンドルを実行して DOM を構築します。これはユーザーにとっては問題ありませんが、クローラーにとっては問題です。生の HTML にはほとんどコンテンツが含まれておらず、すべてがレンダリングに依存しています。

これはデフォルトのスキャフォールドの特性であり、Vue 自体の限界ではありません。Vue コアはサーバーレンダリング(createSSRApp)と静的生成を第一級のパスとしてサポートしており、Vue 自身の SSR ガイドは、ほとんどの本番 SSR/SSG 作業を手作りのセットアップではなく Nuxt に誘導しています。したがって、修正に手を伸ばす前に、アプリが実際に何を出荷しているかを確認してください。レンダリング設定のない素の Vite SPA は CSR です。Nuxt や vite-ssg の背後にある同じアプリは CSR ではありません。

Vue 自身の SSR ガイドは、これをしないことの利点について率直です。サーバーサイドレンダリングでは、「検索エンジンのクローラーは、完全にレンダリングされたページを直接見ることができます。」 その反面、デフォルトで出荷されるのは、JavaScript が実行された後にのみ存在するコンテンツです。 Evidence for this claim Vue server-side rendering sends rendered HTML so crawlers can directly see page content. Scope: Vue SSR benefits; does not guarantee indexing. Confidence: high · Verified: Vue: SSR guide

(Vue 2 は 2023 年 12 月にサポート終了となりました。ここではすべて Vue 3 です。)

Googlebot が Vue アプリを処理する方法

Google は JavaScript を段階的に処理します。生の HTML をクロールし、次に最新のヘッドレス Chromium インスタンス(Web Rendering Service)でレンダリングし、レンダリングされた結果をインデックスに登録します。これから2つのことが導かれます。

  • レンダリングはキューに入れられ、遅延します。 ページはレンダリングキューに置かれます。通常は数秒から数分ですが、急増することもあります。JS の実行後にのみ存在するコンテンツはすぐにはインデックス可能ではありません。生の HTML にあるコンテンツはインデックス可能です。
  • 非同期データが本当のリスクです。 同期 JavaScript は確実にレンダリングされます。マウント後に API から取得されたデータは、確実に取得されるとは限りません。Vue の SSR ガイドは明確に述べています:「アプリがローディングスピナーで始まり、Ajax でコンテンツを取得する場合、クローラーはあなたが終了するのを待ちません。つまり、SEO が重要なページで非同期に取得されたコンテンツがある場合、SSR が必要になる可能性があります。」 実際には:onMounted で取得されたデータはクライアントのみであり、レンダリングしないクローラーには見えません。レンダリングするクローラーでもリスクがあります。

John Mueller は、静的 HTML がほぼ同一で、すべての固有コンテンツが JavaScript に依存する SPA スタイルのセットアップの失敗モードについて説明しています。その JS を適切に実行できない場合、ページは Google にとって同じように見え、焦点は JS で読み込まれたコンテンツではなくボイラープレート HTML に留まります。教訓は、より広範な JavaScript SEO ページと同じです。コンテンツを迅速かつ確実に DOM に取り込むことです。

Bing とソーシャルボットは Google よりもこれが苦手です。 Bing には Google に匹敵するレンダリングパイプラインがなく、ソーシャルプレビュースクローラー(X、Slack、iMessage)は一般的に JavaScript をまったく実行しません。そのため、素の CSR Vue アプリは空の共有プレビューを生成します。Bing のトラフィックやソーシャル共有が重要な場合は、プリレンダリングや SSR は必須です。

Vue Router:ハッシュモードではなく createWebHistory() を使用する

Vue Router には2つの履歴モードがあります。ハッシュモードcreateWebHashHistory())は example.com/#/about のような URL を生成します。Vue Router のドキュメントは、# 以降はサーバーが無視するフラグメントであるため、「SEO に悪影響を与える」 と述べています。 Evidence for this claim Vue Router hash history uses a URL fragment that is not sent to the server and is discouraged for SEO. Scope: Vue Router hash history. Confidence: high · Verified: Vue Router: History modes HTML5 履歴モードを使用してください:

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [/* ... */],
})

履歴モードはクリーンな URL(example.com/about)を提供しますが、サーバーフォールバックが必要です。ルートへの直接リクエストは、Vue が引き継げるように index.html を提供する必要があります。そうしないと、直接アクセスは 404 になります。ホストでそのキャッチオールを設定してください(Nginx の try_files、Netlify/Vercel/Cloudflare での SPA リライトなど)。

そのリライトの範囲を慎重に設定してください。広すぎるキャッチオールは、存在しない静的アセット、実際の API ルート、または実際に 404 にしたいページに対しても index.html を提供します。これにより、以下のソフト 404 ガイダンスが静かに無効になり、壊れたリンクが「機能した」ように見えるページの背後に隠れる可能性があります。

真の404状態に対しては、ソフト404を避けてください。クライアントサイドの「見つかりません」ビューが200を返すと、空のシェルとしてインデックスされる可能性があります。Googleのガイダンスは、実際の404ステータスを返すURLにリダイレクトするか、エラーページに<meta name="robots" content="noindex">を追加し、ビュー間のルーティングにはHistory APIを使用することです。

headとmetaの管理: @unhead/vue

デフォルトでは、すべてのVueルートが1つの<title>と1つのmeta descriptionを共有します。ここでタグの歴史が重要になるのは、古い回答が行き止まりだからです:

  • vue-meta — Nuxt 2時代のライブラリ。レガシー。
  • @vueuse/head — その後継だが、現在はサンセット。
  • @unhead/vue — 現在のコミュニティ標準であり、非NuxtのVue 3アプリで使用すべきものです。

扱いやすい入口は useSeoMeta() コンポーザブルです。型安全かつ XSS に配慮され、Open Graph や Twitter Card を含む 100+ の meta タグに対応しています:

import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  title: 'Vue SEO Guide',
  description: 'How to make a Vue 3 app crawlable and indexable.',
  ogTitle: 'Vue SEO Guide',
  ogDescription: 'How to make a Vue 3 app crawlable and indexable.',
  twitterCard: 'summary_large_image',
})

Metaはリアクティブにできます。getterやcomputed値を渡すと、データが変わったときにタグが更新されます。canonicalタグについては、最も安全なパターンは依然としてHTMLであり、JSではありません: Googleのガイダンスは*“the best way to set the canonical URL is to use HTML,“*であり、JavaScriptで注入する必要がある場合は、常にHTMLが設定するのと同じ値に設定してください。(私はAhrefsでJS canonicalをテストし、Googleがそれらを尊重することを発見しました。Googleがドキュメントに例外を追加するきっかけにもなりましたが、HTMLの方が依然としてリスクが低い道です。)

レンダリング戦略を選ぶ

これが実際に効果を発揮する決断です。フレームワークに依存しないJavaScript SEOページと同じメニューを、Vueに適用したものです。

クライアントサイドレンダリング(CSR)— デフォルトであり、リスクが高いもの。 ログインの背後にあるアプリ的なページ、ダッシュボード、インデックスされる必要がないものには許容されます。ランク付けされるか共有される必要があるコンテンツには許容されません。

vite-ssg によるプリレンダリング。 コンテンツが安定した Vue 3 SPA では、vite-ssg がビルド時に静的 HTML を生成します。ビルドスクリプトを vite build から vite-ssg build に切り替えるだけで、@unhead/vue も組み込まれています。マーケティングサイト、ドキュメント、ブログに適していますが、リクエストごとに大きく変わるページで SSR の代わりにはなりません。webpack 時代の古い prerender-spa-plugin はレガシーで、実質的に保守されていません。現在は vite-ssg または Nuxt を選びます。

サーバーサイドレンダリング。 Vue の公式ガイドは @vue/server-renderer を使う手動 SSR も説明していますが、多くのプロジェクトには自作よりメタフレームワークを明示的に勧めています。単純なケースについては “if you’re only investigating SSR to improve the SEO of a handful of marketing pages … then you probably want SSG instead of SSR.” (翻訳) 「少数のマーケティングページの SEO 改善だけを目的に SSR を検討しているなら、おそらく SSR ではなく SSG が適しています」と述べています。手動 SSR では、アプリ、ルーター、ストアをリクエストごとに新しく作成してください。長時間動作する Node サーバーではモジュール単位のシングルトンが再利用され、ある利用者のデータで変更した共有状態が別のレスポンスへ漏れる可能性があります。Nuxt が多くのプロジェクトに推奨される理由の一つは、この分離を処理するためです。

Evidence for this claim Module-scope singleton state in Vue SSR can leak user-specific data across requests; create application, router and store instances per request. Scope: SSR and hydration Confidence: high · Verified: Server-Side Rendering

Nuxt — 推奨される完全なソリューション。 NuxtはSSRとSSGをすぐに使える状態で提供し、組み込みのuseSeoMeta()とhead管理、そしてsitemap、robots.txt、構造化データのための@nuxtjs/seoモジュールを備えています。SEOが重要なほとんどのVueプロジェクトでは、これがVue自身のドキュメントが指す道です。(Nuxtには独自の深さがあります — 別途カバーされています。これはクロスリンクであり、深掘りではないとお考えください。)

動的レンダリング — しないでください。 ボットにプリレンダリングされたHTMLを、ユーザーにSPAを提供することは常に回避策であり、Googleは2024年にこれを非推奨とし、実装ドキュメントを削除しました。代わりにSSRまたはSSGで構築してください。

ドキュメントに特化して言えば、VitePressはVueネイティブの静的サイトジェネレーターです。すべてのページがプレーンなHTMLとして配信されるため、JSレンダリングの障壁がなく、SEOはfrontmatter(titledescriptionhead)またはcanonical/動的タグ用のtransformHeadビルドフックで設定されます。

ハイドレーションの不一致は、パフォーマンスの問題だけでなくSEOの問題でもある

SSR/SSG を行う場合、クライアントは createSSRApp()(通常の createApp() ではありません)でマウントし、サーバーが生成した HTML をゼロから作り直すのではなくハイドレーションします。サーバーの HTML とクライアント側のレンダリングが一致しないと、Vue は不一致のノードを破棄して再レンダリングします。SEO の観点では、Google がサーバーレンダリング版からインデックスした内容と、ハイドレーション後にユーザーが見る内容が異なる可能性があります。これは単なるちらつきではなく、品質シグナルの不一致です。よくある原因は、無効な HTML の入れ子、テンプレート内のランダム値、サーバーとクライアントで異なる日時です。Vue 3.5+ では、意図的な差異について不一致の警告を選択的に抑える data-allow-mismatch が追加されました。ただし、これはコンソールを静かにするだけで、サーバーとクライアントの出力を同等にするものではありません。診断していない不一致を隠すためだけには使わないでください。

Core Web VitalsはVue固有の関心事です

デフォルトのCSR Vueは、最大のコンテンツが描画される前にダウンロード、解析、実行する必要がある大きなJSバンドルを配信するため、何もしなければLCPが低下します。対策は以下の通りです。

  • コード分割(Vite のデフォルト)と遅延読み込みルートを使い、アプリ全体を最初から配信しないようにします。
  • fetchpriority="high" を LCP のヒーロー画像に設定します。
  • Vapor Mode は、対象コンポーネントで仮想 DOM を迂回するオプトインのコンパイラモードで、SSR ページのハイドレーションコストを削減できる可能性があります。対象は Vue 3,6 で、3,5 ではありません。2026 年半ば時点ではまだ実験段階(ベータ/リリース候補)で、安定版の 3,5.x 系には含まれていません。注視する価値はありますが、現時点の本番環境で依存すべき機能ではありません。

Vueでの構造化データ

Google は構造化データを読み取る前に JavaScript を実行するため、JSON-LD の注入は機能します。信頼できるパターンは、@unhead/vueuseHead()script を設定し、その type を application/ld+json にすることです。レンダリングに依存するため、Google が認識したと決めつけず、URL Inspection で確認してください。

位置づけ

Vue SEOは、一般的なJavaScript SEO問題(パリティ、インタラクション、状態、タイミング)の一例であり、ヘッドレスCMSの状況とほぼすべてを共有しています。そこでは、フロントエンドのレンダリングモードが結果を決定します。

上記のすべてのオプションに当てはまる注意点が1つあります。SSRとSSGはコンテンツをHTMLに取り込みますが、どちらもインデックス、ランキング、Core Web Vitals、またはハイドレーションがサーバー出力と完全に一致することを保証しません。これらはJavaScriptレンダリングの障壁を取り除くだけで、残りのSEO(および正確性)は依然としてあなた次第です。

1つだけ覚えておくなら:コンテンツをHTMLに取り込むこと。 それ以外はすべて詳細です。

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.