クライアントサイドJavaScriptフレームワーク
React、Vue、Angular、Svelte、SolidJSに共通するSEO問題を説明します。クライアントサイドレンダリングは空のシェルを送り、解決策はhead管理とレンダリング戦略を組み合わせることです。
言語
React、Vue、Angular、Svelte、SolidJSは、既定ではほぼ空のHTMLシェルを送り、ブラウザーでページを構築するUIライブラリです。クローラーはJavaScriptが実行されるまで空のページを見る可能性があり、Googleはレンダリングできますが遅延キューで処理し、BingやAIクローラーははるかに不確実です。共通する修正は、(1)ルートごとのメタタグを管理するheadパッケージと、(2)prerender、SSR、対応するmeta-frameworkというレンダリング戦略です。このハブでは共通問題と修正を説明し、フレームワーク別ガイドへ案内します。
要点 — React、Vue、Angular、Svelte、SolidJSは、開発者がインタラクティブなサイトを作るためのツールです。既定ではブラウザーにほぼ空のHTMLページを送り、JavaScriptで実際のコンテンツを組み立てます。ユーザーには便利ですが、SEOには危険です。検索クローラーが空白のページへ到達する可能性があるからです。5つすべてに共通する修正は、ページごとに
<title>とメタタグを管理し、JavaScriptが実行される前にコンテンツがHTMLに存在するようにすることです。
クライアントサイドフレームワークとは
クライアントサイドフレームワークは、最初のHTMLレスポンスの後にブラウザーでルートのコンテンツをレンダリングできます。 Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: MDN: Client-side frameworks GoogleはJavaScriptをレンダリングできますが、リソースの利用可能性とレンダリングの状況も処理される内容に影響します。 Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics
クライアントサイドフレームワークは、訪問者のブラウザーでページを構築するJavaScriptライブラリです。最もよく使う5つは、React、Vue、Angular、Svelte、SolidJSです。現代のウェブアプリとダッシュボードの多くは、これらで構築されています。
注意点は「client-side」という言葉にあります。既定では、これらのフレームワークはおおむね次のような小さなHTMLファイルを送ります。
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>そのHTMLにはコンテンツがありません。空のコンテナとスクリプトだけです。ブラウザーがスクリプトをダウンロードして実行し、その後に見出し、本文、リンクなどが現れます。この既定の動作が**クライアントサイドレンダリング(CSR)であり、この方式で作ったサイトはしばしばシングルページアプリケーション(SPA)**と呼ばれます。
SEOにとって問題になる理由
検索クローラーは、ページをクリックして回る人間ではありません。Googlebotなどのクローラーがページを取得したとき、最初に受け取るのは空のシェルです。クローラーがJavaScriptを実行しなければ、インデックス登録するコンテンツのない空白のページとして見えます。
GoogleはJavaScriptを実行できます。そのため通常は最終的にコンテンツを確認します。しかし、次の点に注意が必要です。
- レンダリングは遅延します(レンダリングは別のキューに入る工程です)。
- ChatGPTのようなツールへページを提供するBingやAIクローラーなど、他のクローラーはJavaScriptの実行がはるかに不安定です。
したがって、「自分のブラウザーでは動く」ことは、「検索エンジンから見える」ことを意味しません。
5つすべてに共通する修正
どのフレームワークを選んだかにかかわらず、解決策は2つの部分から成ります。
- headを管理する。 各ページには固有の
<title>とメタディスクリプションが必要です。単純なCSRアプリはHTMLファイルが1つなので、手を加えなければすべてのページで同じタイトルになります。各フレームワークにはこれを解決する小さなパッケージがあります(詳しくはAdvancedタブ)。 - レンダリング戦略を選ぶ。 JavaScriptが実行される前にコンテンツをHTMLへ入れます。prerendering(事前に静的HTMLを構築する)、server-side rendering(SSR)、または対応するmeta-framework(ReactならNext.js、VueならNuxtなど)へ移行する方法があります。
フレームワークごとの詳細、つまりどのheadパッケージを使うか、どのレンダリング方式を選ぶか、Googleがこれらのアプリを実際にどう扱うかを知りたいですか。Advancedタブへ切り替え、フレームワーク専用ガイドへ進んでください。
要点 — React、Vue、Angular、Svelte、SolidJSはすべて、既定ではクライアントサイドレンダリングを行うUIライブラリです。ほぼ空のHTMLシェルを送り、ブラウザーでDOMを構築します。5つに共通するSEO上の問題は、クローラーが空のシェルを受け取り、コンテンツがJS実行後にしか存在しないことです。Googleはこれらのアプリを遅延したキュー方式でレンダリングしますが、BingとAIクローラーははるかに不確実です。修正も共通で、(1)
<title>/メタ用のルート単位パッケージによるhead管理と、(2)prerendering、SSR、対応するmeta-frameworkへの移行というレンダリング戦略です。フレームワーク間の違いは主に、どのパッケージとどの戦略を選ぶかです。以下の各深掘りで扱います。
フルフレームワークではなくライブラリであることが根本原因
フレームワークのアーキテクチャはさまざまなので、クライアントレンダリングは自動的にインデックス登録の失敗になるわけではありません。 Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: MDN: Client-side frameworks サーバーレンダリングまたはprerenderingは、クローラー側のJavaScript実行への依存を減らしますが、インデックス登録を保証するものではありません。 Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics
React、Vue、Angular、Svelte、SolidJSは、主にUIレンダリングライブラリです。データをDOMへ変換し、状態が変わるとDOMを同期させます。初期状態ではDOMがブラウザー内で構築されます。これが高速でアプリらしい操作感を生む一方、SEO上の問題も生みます。
既定のビルドは、空のマウントノード(<div id="root">、<div id="app">、<app-root>)とJavaScriptバンドルを含むHTMLシェルを送ります。検索エンジンが必要とする見出し、本文、内部リンク、構造化データは、バンドルのダウンロードと実行後に注入されます。JSが実行される前には、何もありません。
これはクライアントサイドレンダリングです。meta-frameworkやビルド時のprerenderステップを追加する前の、素のライブラリにおける初期動作です。バグではなく、最初に与えられる既定値です。しかし「既定」は「永続的」でも「普遍的」でもありません。バージョン、使用したCLIやスターターによって変わり、同じアプリ内でも、作り方によって2つのルートが異なるレンダリング方式になることがあります(マーケティングページはprerender、ダッシュボードは純粋なCSRのまま、など)。フレームワーク名だけで動作を決めつけず、特定のビルドの特定のルートが実際に何を送るかを確認してください。
共通する問題:空のシェル
Googleは、JSアプリをクロール、レンダリング、インデックス登録という段階で処理すると明記しており、“without rendering Google might not see that content.” (翻訳)「レンダリングしなければ、Googleはそのコンテンツを見られない可能性があります」と説明しています。CSRアプリでは、すべてのコンテンツがそのレンダリング工程の背後にあります。そこから3つの帰結が生じます。
- レンダリングは遅延し、待ち時間は固定されていない。 レンダリングはクロール後の別キュー工程です。Googleはクロール、レンダリング、インデックス登録を3つの別工程として説明していますが、すべてのページに共通する待ち時間は約束していません。遅延はURLと、その時点のGoogle側のリソース配分によって変わります。ページでレンダリングが完了するまで、どれほど時間がかかっても、コンテンツはインデックス登録用に存在しません。
- Google以外のクローラーを前提にできない。 BingのJavaScriptレンダリングは一貫せず、ほとんどのAIクローラー(LLMやAI検索向けにページを取得するボット)はJSをほとんど、またはまったく実行しません。これらは別会社の別インフラなので、Googleのドキュメントから一般化できません。Googleや昨年のテストと同じだと決めつけず、各プロバイダーの現在の動作を確認してください。CSRだけのサイトは、レンダリングしないクローラーからほぼ見えなくなるリスクがあり、AIクローラーは増えつつあります。
- ページごとのメタデータが欠ける。 HTMLファイルが1つなら、ルートごとにheadを積極的に管理しない限り、すべてのルートで
<title>とメタディスクリプションが1つずつになります。
共通する修正その1:head管理
SPAはHTMLドキュメントが1つなので、ユーザー(およびクローラーのレンダラー)がルート間を移動するときに、ドキュメントのheadを更新するコードが必要です。すべてのフレームワークには、そのための標準パッケージまたは組み込みAPIがあります。
- React →
react-helmet-async(またはNext.jsへ移行した場合はフレームワークのメタデータAPI)。 - Vue →
@unhead/vue(NuxtのSEOユーティリティの基盤)。 - Angular →
@angular/platform-browserの組み込みTitle/Metaサービス。追加依存関係は不要です。 - Svelte → 組み込みの**
<svelte:head>要素**。 - SolidJS →
@solidjs/meta(SSR経路ではSolidStart)。
head管理で正しく固有のメタタグを設定できますが、それだけでは空のシェルの問題は解決しません。タグもJS実行後にしか現れないからです。そのため、パート2も必要です。
共通する修正その2:レンダリング戦略
JavaScriptが実行される前に実コンテンツ(およびheadタグ)をHTMLへ入れるには、3つの方式から選びます。SEOリスクをどれだけ減らすかで並べると、次の順です。
- prerendering/静的生成(SSG)。 ビルド時に各ルートの静的HTMLを作ります。リクエストごとに変わらないコンテンツならリスクが最も低い方式です。各ライブラリにはprerender経路があります(SolidJS組み込みprerender、Vueのprerenderプラグイン、Angularのprerenderingなど)。
- サーバーサイドレンダリング(SSR)。 リクエストごとにサーバーでHTMLをレンダリングし、ブラウザーでhydrateします。ここでmeta-frameworkが登場します。Next.js(React)、Nuxt(Vue)、Angular SSR(旧Angular Universal)、SvelteKit(Svelte)、SolidStart(SolidJS)です。ランキングが必要なコンテンツサイトの多くでは、対応するmeta-frameworkの採用が最もきれいな修正です。
- 完全なCSRのまま、クロール可能にする。 ランキングが不要なログイン後のアプリ画面なら許容できることがありますが、検索に出したいものには悪い既定値です。
この判断はアプリ単位ではなく、ルート単位で行います。同じコードベースでも、マーケティングページとログイン済みダッシュボードは、リストの別の行に入って当然です。各ルートについて次を問いかけます。
- 出力 — コンテンツは初期レスポンスに必要か、それともJS実行後に現れてもよいか。
- 鮮度 — 一度ビルドできるほど安定しているか(prerender)、リクエストごとに変わるか(SSR)。
- パーソナライズ — 訪問者ごとに異なるか。prerenderでは対応できず、SSRとCSRの選択になります。
- サーバーコスト — SSRはリクエストごとに計算を追加し、prerenderはそのコストをビルド時に前倒しします。
- JS依存 — ルートの有用性は、クライアントJavaScriptが実行されることにどれだけ依存するか。
- 失敗時の挙動 — JSが失敗またはブロックされたとき、ルートは使える状態へ劣化するか、それとも何もなくなるか。
フレームワークにかかわらず、判断の核心は同じです。このコンテンツはランキングまたは引用される必要があるか。 答えが「はい」なら、サーバーレンダリングまたはprerenderされたHTMLへ入れます。純粋にインタラクティブなアプリUIならCSRで問題ありません。
Googleはこれらのアプリをどう扱うか(そして他社が同じでない理由)
Googleは、これらのフレームワークをすべてレンダリングできます。常に更新されるheadless Chromeを実行してJSを動かします。しかし処理は遅延キューに入り、レンダラーはステートレスです(保存されたcookie/localStorage、service worker、操作状態はなく、スクロールもクリックもしません)。したがって、フレームワーク選択に加えて、JavaScript SEOハブのJS-SEOルールも適用されます。実際の<a href>リンク、raw DOMとrendered DOMの一致、操作の背後に隠さないコンテンツ、JSでnoindexを注入しないことが重要です。
Google以外では状況が悪くなります。BingのJSレンダリングは不安定で、AIクローラーの多くはまったくレンダリングしません。CSRアプリでは、コンテンツがGoogleには(最終的には)存在しても、Bingや、検索に使う人が増えているAIツールには存在しない可能性があります。SSRまたはprerenderingなら、Googleだけでなくすべてのクローラーとの隔たりを埋められます。CSRだけのコンテンツを出荷しない最大の理由です。
5つのフレームワークを一覧で比較
| フレームワーク | 既定値 | head管理 | SSR/meta-framework | SEO上の注意 |
|---|---|---|---|---|
| React | CSR | react-helmet-async | Next.js(Metadata API) | CSR優先SPAで最も一般的。Next.jsが標準的なSEO修正 |
| Vue | CSR | @unhead/vue | Nuxt(useSeoMeta()) | NuxtはSSRが既定。素のVueではprerenderまたはNuxtが必要 |
| Angular | CSR(SPA) | 組み込みTitle/Metaサービス | Angular SSR(旧Universal) | 大規模SPA。現代のAngularはSSRと段階的hydrateを追加 |
| Svelte | CSR(Svelte)/SSR(SvelteKit) | <svelte:head> | SvelteKit(SSRが既定) | SSRが既定だが、ssr:falseの静的トラップに注意 |
| SolidJS | CSR | @solidjs/meta | SolidStart | 細粒度リアクティビティ。SolidStartがSSRとprerenderを追加 |
パターンは一貫しています。CSRという既定値、headパッケージ、そしてレンダリング戦略(通常は対応するmeta-framework)です。異なるのは名前と、いくつかの注意点です。
次に読むもの:フレームワーク別の深掘り
このハブは地図です。各フレームワークには、固有のパッケージ、設定、落とし穴を説明するガイドがあります。
- React SEO — CSR優先のReactがインデックス登録リスクを生む理由、React RouterとHistory API、
react-helmet-async、Next.jsを選ぶタイミング。 - Vue SEO — Vue 3のCSR既定値、
createWebHistory()、@unhead/vue、meta-frameworkなしのprerendering、Nuxtを選ぶべき場面。 - Angular SEO — AngularのSPA既定値、
@angular/ssr、組み込みのTitle/Metaサービス、prerendering、段階的hydrate。 - Svelte SEO — SvelteとSvelteKitの違い、SvelteKitのSSR既定値、
<svelte:head>、adapter-static+ssr: falseのトラップ、AIクローラーへの含意。 - SolidJS SEO — SolidJSのCSR既定値、
@solidjs/meta、SSRとprerenderingのためのSolidStart、細粒度モデルがレンダリング出力へ与える影響。
CSR、SSR、SSG、ISR、hydrate、dynamic renderingというレンダリング方式と、より広いレンダー/パリティルールについては、親のJavaScript SEOハブを参照してください。
AI要約
Advanced版を短くまとめます。
- 共通する出発点。 React、Vue、Angular、Svelte、SolidJSは、初期状態ではクライアントサイドレンダリングです。
<div id="root">とバンドルを含むほぼ空のHTMLシェルを送り、ブラウザーでDOMを構築します。ただし既定値はバージョン、スターター、meta-frameworkで変わり、同じアプリ内でもルートごとに変わることがあります。フレームワーク名で決めつけず、特定のルートが実際に何を送るかを確認してください。 - Googleはレンダリングするが、待ち時間は固定されていない。 レンダリングはクロール後の別キュー工程で、URLごとに変わります。レンダラーはステートレスで、スクロールやクリックはしません。
- 他のクローラーは前提にできない。 BingのJSレンダリングは一貫せず、ほとんどのAIクローラーはレンダリングしません。別会社の動作をGoogleのドキュメントから一般化せず、各プロバイダーの現在の仕様を確認します。
- 共通する修正は2つ。 (1) head管理 — ルートごとの
<title>/メタ用パッケージ:Reactのreact-helmet-async、Vueの@unhead/vue、Angularの組み込みTitle/Meta、Svelteの<svelte:head>、SolidJSの@solidjs/meta。(2) レンダリング戦略 — prerender/SSG、SSR、または対応するmeta-framework(Next.js/Nuxt/Angular SSR/SvelteKit/SolidStart)。 - head管理だけでは足りない。 タグもJS実行後にしか現れないため、シェルを埋めるレンダリング戦略が必要です。
- ルートごとに判断する。 出力時点、鮮度、パーソナライズ、サーバーコスト、JS依存、失敗時の挙動を、アプリ単位ではなく検討します。ランキングや引用が必要なルートはサーバーレンダリングまたはprerender HTMLへ入れ、ログイン後だけのアプリUIならCSRで構いません。
公式ドキュメント
検索エンジンと各フレームワークによる一次資料です。
- JavaScript SEOの基礎を理解する — クロール→レンダリング→インデックス登録の段階、クロール可能なリンク、レンダリング済みHTMLのテスト。
- 検索関連のJavaScript問題を修正する — クライアントサイドルーティング後のソフト404、History API、レンダラーの制約。
- Google検索の仕組みの詳細ガイド — クロール→インデックス→配信のどこにレンダリングが位置するか。
Bing/Microsoft
- bingbotシリーズ:JavaScript、動的レンダリング、クローキング。なんてこと! — BingがJSレンダリングをどう捉え、動的レンダリングがなぜ存在するかを説明します。
フレームワーク(head+レンダリング)
- Reactドキュメント — CSR優先SPAを広めたライブラリです。Next.jsのメタデータ も参照してください。
- Vue.js — レンダリング/SSR と NuxtのSEOユーティリティ。
- Angular — サーバーサイドレンダリング と、
Title/Metaサービス(Title /Meta)。 - SvelteKit — ページオプション(SSR/prerender) と
<svelte:head>。 - SolidStart — SSRとprerendering と
@solidjs/meta。
出典からの引用
共通するCSRの問題と修正を裏付ける、記録に残る発言です。各検索エンジンのリンクは、引用箇所へ移動するテキストフラグメント付きの深いリンクです。
Google — レンダリングとシェルが重要な理由
- “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” (翻訳)「GoogleはJavaScriptウェブアプリを、1.クロール、2.レンダリング、3.インデックス登録という3つの主要段階で処理します。」 引用へ移動
- “Rendering is important because websites often rely on JavaScript to bring content to the page, and without rendering Google might not see that content.” (翻訳)「ウェブサイトはコンテンツをページへ表示するためにJavaScriptへ依存することが多く、レンダリングがなければGoogleはそのコンテンツを見られない可能性があるため、レンダリングは重要です。」 引用へ移動
- “Google can only discover your links if they are <a> HTML elements with an href attribute.” (翻訳)「Googleがリンクを発見できるのは、リンクがhref属性を持つ<a> HTML要素である場合だけです。」これはすべてのフレームワークのルーターに当てはまります。 引用へ移動
- “Google Search does not interact with your page.” (翻訳)「Google検索はページを操作しません。」レンダラーはコンテンツを表示するためにスクロールもクリックもしません。 引用へ移動
Patrick Stox(私自身の執筆 — JavaScript SEO:決定版ガイド)
- “Any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines.” (翻訳)「どのようなSSR、静的レンダリング、prerenderingの構成でも検索エンジンには問題ありません。」これはこのハブにある全フレームワークの共通線です。
- レンダラーはraw HTMLとrendered HTMLのうち、最も制限の強いrobotsディレクティブを採用します。そのため、CSR側で
noindexを注入するフレームワークは、シェル側がindexでもページをインデックスから外せます。
クライアントサイドフレームワークSEOチェックリスト
React、Vue、Angular、Svelte、SolidJSのいずれにも使えるチェックです。
- 現在のアプリがCSR、SSR、prerenderのどれかを把握している(View Sourceを確認し、コンテンツがraw HTMLにあるか、空のマウントノードだけかを見る)。
- ランキングまたは引用が必要なコンテンツが、サーバーレンダリングまたはprerenderされたHTMLにある。JS実行後だけに注入されていない。
- ルートごとの**
<title>とメタディスクリプション**を管理しており(headパッケージまたは組み込みAPI)、rendered HTMLでページごとに固有である。 - ルーターのリンクが実際の**
<a href>アンカー**である(#フラグメントルーティングや<div>のonclickではない)。 - JavaScriptとCSSを
robots.txtでブロックしていない(Googleはブロックされたファイルからレンダリングしない)。 - コンテンツをスクロール、クリック、ホバーの背後に隠していない。
- クライアントサイドの「見つかりません」画面が実際の**
404**を返すか、noindexを持つ(ソフト404のシェルではない)。 - JSがraw HTMLと矛盾する**
noindex**を注入していない(Googleは最も制限の強い方を採用する)。 - GoogleだけでなくBingとAIクローラーも検討している。SSR/prerenderが、それらに対する唯一の信頼できる回答です。
- 自分のブラウザーだけでなく、URL Inspection(rendered HTML、スクリーンショット、コンソール)で検証している。
これらのチェックは、複数の異なる出力を1ページにまとめています。各段階を個別に検証してください。あるルートが1段階を通過しても、次で失敗することがあります。
| 段階 | 確認すること |
|---|---|
| 直接レスポンス(JS無効/ブロック) | JSを無効にしてURLを取得する。固有の見出しと本文があるか、マウントノードだけか。 |
| ストリームされたチャンク(ストリーミングの場合) | コンテンツが段階的に届くか、それとも遅いチャンクが後続すべてを止めるか。 |
| rendered DOM(JS実行後) | バンドル実行後の最終DOMが完全か。見出し、リンク、構造化データがすべてあるか。 |
| hydrate | クライアントがきれいに引き継ぐか、コンソールエラーやhydrateの不一致が出るか。 |
| クライアントナビゲーション | アプリ内のルート変更が、直接読み込みと同じようにURL、タイトル、canonicalを更新するか。 |
| ステータスコード | 実際の404/410/5xxルートが、200内のクライアント表示メッセージではなく、そのステータスを直接返すか。 |
| メタデータ | rendered <title>、description、canonical、robotsディレクティブが、単に存在するだけでなくルートごとに正しいか。 |
フレームワーク別の修正一覧
| フレームワーク | 既定レンダリング | head管理 | SSR/meta-framework | prerender経路 |
|---|---|---|---|---|
| React | CSR | react-helmet-async | Next.js | Next.js SSG/react-snap |
| Vue | CSR | @unhead/vue | Nuxt | Nuxt nuxi generate/prerenderプラグイン |
| Angular | CSR(SPA) | 組み込みTitle/Meta | Angular SSR(旧Universal) | ng build prerender |
| Svelte | CSR(Svelte)/SSR(SvelteKit) | <svelte:head> | SvelteKit | adapter-static(ssr:falseに注意) |
| SolidJS | CSR | @solidjs/meta | SolidStart | SolidStart prerender |
2つの修正(これを覚える)
- head管理 → ルートごとに固有の
<title>/メタ。 - レンダリング戦略 → prerender(SSG)またはSSRまたは対応するmeta-framework。head管理だけでは空のシェルを埋めません。
リスク階段(SEOリスクが低い順)
| 方式 | SEOリスク | 用途 |
|---|---|---|
| Prerender/SSG | 最低 | リクエストごとに安定したコンテンツ |
| SSR(meta-framework) | 低 | ランキングが必要なリクエスト単位/動的コンテンツ |
| Hydration(isomorphic) | 低 | アプリとコンテンツの混合 |
| 完全CSR | 最高 | ランキング不要のログイン後アプリUI |
クローラーの現実チェック
| クローラー | JSを実行するか |
|---|---|
| Googlebot | はい — ただし遅延、キュー方式、ステートレス |
| Bingbot | 一貫しない |
| AIクローラー(LLM/AI検索) | ほとんどいいえ |
CSRだけのコンテンツはGoogle以外ではどこでも賭けです。Googleでさえ遅延します。SSR/prerenderなら、すべてのクローラーに対する賭けをなくせます。
クライアントサイドフレームワークでよくあるSEO問題
検索ツールに空のページまたはアプリシェルだけが表示される
症状: Raw HTMLには#root、#app、app-rootのようなマウント要素しかなく、表示されたページには実際の本文がある。原因の可能性: ルートが完全にクライアントレンダリングされている。修正: 安定したルートをprerenderするか、ルートをSSR対応のmeta-frameworkへ移す。JavaScriptを無効にしてURLを取得し、レスポンスに固有の見出しと本文があることを確認して修正を証明する。
すべてのルートで同じタイトルまたはcanonicalになる
症状: 複数のURLで異なる表示をレンダリングしているのに、同じタイトル、description、canonicalを公開している。原因の可能性: 共通HTMLシェルがheadを所有し、ルート変更がheadを更新していない。修正: フレームワーク固有のhead APIを使い、ルートデータからメタデータを設定する。各ルートの最終DOMに、自己参照canonicalが1つと固有のタイトルがあることを確認する。
ユーザーにはリンクが機能するが、クローラーがルートを発見しない
症状: ブラウザーではナビゲーションが機能するのに、リンクされたルートが発見されない。原因の可能性: ボタンまたはdiv要素のクリックハンドラーが、クロール可能なアンカーを置き換えている。修正: 実際の<a href="...">リンクをレンダリングし、ルーターに拡張させる。クリックしなくても、rendered DOMのhrefに遷移先が現れることを確認する。
コンソールにhydrateエラーまたは内容の不一致が表示される
症状: サーバーレンダリングまたはprerenderされたHTMLは正しいが、ブラウザーのコンソールにhydrate警告が出る、または読み込み直後にコンテンツが一時的に表示されて変わる。原因の可能性: サーバー出力とクライアントの初回レンダリングが一致していない。日付/ロケール形式、ランダムID、初回レンダリング中に実行されるwindow依存コードなどが原因です。修正: 同じ入力に対してサーバーとクライアントが決定論的にレンダリングするようにし、ブラウザー専用の処理はhydrate後に実行する。JS有効でルートを読み込み、コンソールにhydrateエラーが0件であることを確認する。
ブラウザーではルートの状態が変わるが、直接URLが一致しない
症状: アプリ内をクリックすると動作するページが表示されるが、同じURLを直接リクエストした場合(または更新後)には、別の結果、つまり汎用シェル、誤ったステータスコード、古いメタデータが返る。原因の可能性: クライアントナビゲーションがブラウザー内の表示を更新しているだけで、対応するサーバー側ルートハンドラーがない。クライアント遷移後に存在する状態が、単独でリクエストできる実ページではない。修正: ナビゲーションで到達できるすべてのルートが直接リクエスト可能で、同じコンテンツ、ステータス、メタデータを返すようにする。クリックではなくURLを新規に読み込み、まずJS無効、次にJS有効で確認する。
自分で確認:クライアントサイドフレームワーク
React、Vue、Angular、Svelte、SolidJSに共通するSEO問題と修正についての5問です。それぞれ答えを選び、あとで確認してください。
時間を使う価値のあるリソース
私の関連執筆
- JavaScript SEO:決定版ガイド — レンダリング、DOMパリティ、最も制限の強いディレクティブのルール、レンダリング構成の選び方を扱う総合ガイドです。このハブの全フレームワークの基礎です。
- テクニカルSEO初心者向けガイド — クライアントサイドレンダリングとJavaScript SEOを、より大きな全体像の中に位置付けます。
私の講演
- 検索の仕組み (SlideShare) — クロール、レンダリング、インデックス登録、ランキングを説明する講演です(次の常設の注意書きを含みます:“This is my understanding of systems… not going to be 100% complete or accurate.” (翻訳)「これはシステムについての私の理解であり、100%完全または正確とは限りません。」)。
業界の資料
- web.dev — Webでのレンダリング — CSR、SSR、SSG、hydrateを比較するChromeチームの基準解説で、レンダリング戦略の部分を考えるための、最も優れたフレームワーク非依存のモデルです。
- Google Search Central — JavaScript SEOの基礎 — クロール→レンダリング→インデックス登録の工程とクロール可能なリンクに関する公式一次資料です。
- Google Search Central — 検索関連のJavaScript問題を修正する — クライアントサイドルーティング後のsoft-404sと、すべてのSPAルーターが使うHistory APIを扱います。
- Martin SplittのJavaScript SEOプレイリスト — JSアプリをGoogleがどう扱うかを説明する、フレームワーク非依存の公式動画シリーズです。
- Onely — JavaScript SEOハブ — 専門エージェンシーによるレンダリングとJS-SEO監査の技術記事です。
変更履歴
2026年8月22日に更新。
編集概要と記録された変更の詳細。変更の詳細
-
変更の詳細な注記は現在英語でのみ提供されています。
完全な比較は利用できません — この改訂の以前のスナップショットがアーカイブされていません。
2026年8月8日に更新。
編集概要と記録された変更の詳細。変更の詳細
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
完全な比較は利用できません — この改訂の以前のスナップショットがアーカイブされていません。
2026年7月17日に更新。
編集概要と記録された変更の詳細。変更の詳細
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
完全な比較は利用できません — この改訂の以前のスナップショットがアーカイブされていません。