SPAを開発するエンジニアこそ知るべき、正しく評価されるためのSEO

# SPAによるWebサイト開発とSEO

昨今はReactをはじめとするフロントエンドのライブラリやフレームワークの台頭により、比較的多彩な機能を持つWebアプリケーションだけでなく、メディアのようなWebサイトをSPA(Single Page Application)で構築する例も見られるようになってきました。こうしたWebサイトにおいて、SEOは重要な集客手段の１つです。

ところで、SEOに関わっている方や造詣の深い方はディレクターやマーケティング寄りの方が多いようです。そのせいかSPAでサイトを構築する場合のSEOに関する話題はあまり目にしません。またエンジニア界隈では技術寄りのトピックへの関心がメインで、SPAでのSEOといえば、SSR(Server-Side Rendering)の実現方法くらいしか話題にならないように感じています。

筆者はどちらかといえばサーバサイドの方が本職ではあるのですが、以前エンジニアとしてSEOにも少し携わっていたことに加え、最近はフロントエンドをメインで開発をする機会もあったので、このトピックについて筆者なりの考え・注意すべき点をまとめてみました。

## SEOにおけるエンジニアの役割

SEOを実践する上でのエンジニアの役割は、多くのキーワードで検索結果の上位へ表示させたり、検索経由の流入を直接増やすことではありません。検索エンジンに適切に評価してもらえるようクローラーへ情報を伝え、期待通りにインデックスしてもらうことです。

そのため、これから述べるようなことを実践しても、望んだキーワードで検索結果の上位に表示されるとは限りません。一方で気をつけていないと、実装次第でサイト上のコンテンツやその価値を正しく伝えられなくなることはあり得ます。

要するに、可能な限り機会損失を避け、正しく価値を伝えることがエンジニアの役割であると考えます。

# SPA開発で気にするべきSEOの諸問題

以下では、クライアントサイドでHistory APIなどを使用せず、1ページごと毎回サーバサイドでレンダリングするWebサイトをレガシーなサイトと呼ぶことにします。（決して古いという意図ではなく、あくまで従来のWebサイトとSPAを区別するためにこう呼称します。）

## HTTPステータスコードを正しく通知する

存在するページなら200、ページのURLが移動した場合は301、存在しないページは404（または410）などと、正しいHTTPステータスコードでレスポンスを返すことです。Railsを始めとするサーバサイドのWebフレームワークではほぼ標準的に持っている機能なので、あまり意識されないこともあるかもしれませんが、SPAでも同じように正しくステータスコードを返してあげる必要があります。

### 正しくないステータスコードを返すとどうなるか？（例: ソフト404エラー）
これに起因する問題の一例として、[ソフト404エラー](https://support.google.com/webmasters/answer/181708?hl=ja)などが挙げられます。本来は存在しない Not Found を返すべきページで、見かけ上は404風のページを表示しつつ、HTTPステータスコードとしては404を返すべきページで200を返してしまっているケースです。

本来存在しないようなページを存在するページとしてしまった結果、無駄なクロール・インデックスが行われ、「ページがありません」といったページがインデックスされたり、本来クロールしてほしいコンテンツがクロールされなくなる、といった問題が生じる可能性があります。

Googleもこの問題は認識しており、できる限りそうしたケースでも、ソフト404エラーがあると疑わしい場合、[Google Search Console](https://www.google.com/webmasters/tools/home?hl=ja)で確認できるようになっています。しかし404であることを確実に判定することは難しいので、正しいステータスコードでレスポンスを返すべきです。

## レンダリングにまつわる問題

フロントエンドの開発をしているエンジニアの方と話すと、しばしば以下のような話を耳にします。

- GoogleはJavaScriptを解釈・実行できるようになっているから大丈夫ではないか？
- AngularJSはGoogleのプロダクトだから多分なにかしら対応してくれるだろう
- SSR(Server-Side Rendering)しておけば大丈夫

いずれも間違いともいえませんが、万事問題ないと考えるのは少々早計です。

### クローラーは正しくJSを実行できるのか？

SPAとして実装されたWebアプリケーションで、[TrackJS](https://trackjs.com/)を使いクライアントサイドで発生するエラーをトラッキングしてみると、モダンブラウザはもちろんIE11など少々レガシーなブラウザでもエラーが発生しないようなケースで、Googlebotでのみエラーが発生してしまう状況が見られました。

上記の事象から、今後改善される可能性も十分あるのですが、少なくとも2017年2月現在の筆者の観測範囲では、GooglebotのJS実行エンジンは、モダンブラウザに比べてレガシーな実装であると推測しています。

またSPAの場合、ロード完了のタイミングが判定しづらいという点も問題だと考えています。SPAの場合 [Navigation Timing API で定義されている domComplete](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/measure-crp?hl=ja) 以降のタイミングでも、コンテンツをロードすることがあるように思いますが、これをGooglebotがどこまで正しく判定できるのかはGooglebot次第、という印象です。

### SSRであればOKなのか？

SPAでも、SSRに対応できるなら対応する方が望ましいと思います。GooglebotのようにJavaScriptを解釈・実行できるクローラーだけではなく、まだまだレガシーなクローラーも存在します。また先に述べたようにGooglebotであってもJavaScriptの実行でエラーとなるケースがありますが、その場合もSSRであればレンダリングは正しく行われるはずです。

ただ、SSRにすればそれだけで全てが解決でもありません。SSRでも問題のあるケースを次に述べておきます。

## 評価される内部リンク・評価されない内部リンク

SEOにおいて、数年前に比べてコンテンツが重視されているとはいえ、リンクによる評価は今でも重要です。SPAによるサイト構築で特に気をつけなければならないのは、内部リンクです。

レガシーなWebサイトの場合、ページ遷移は通常a要素で記述します。JavaScriptで表示コンテンツを切り替えたりすることはあっても、ページ遷移自体をJavaScriptで記述することは稀だと思います。

ですがSPAの場合、必ずしもa要素だけがページ遷移のトリガーではないはずです。他の要素のクリックなどをトリガーとして、History APIによりクライアントサイドでURLの変更を取り扱うこともできるのですが、a要素によるリンクとして実装していないと、内部リンクとしては扱われません。

ちなみに例えば [react-router](https://github.com/ReactTraining/react-router) で提供されている `<Link>` コンポーネントの場合、History APIによるURL制御を提供しつつも、DOMとしては通常のa要素によるリンクを生成してくれるため問題なさそうです。ですが特に自分でHistory APIを操作する場合には、History APIのトリガーとなっている要素も正しくリンクになっているかなどを注意する必要があります。

### リンクはページの発見手段でもある

新規のページを用意したら、クローラーにページを発見してもらう必要があります。Googleはさまざまなシグナルをページの発見手段に用いているようですが、既知のページのリンクを通じて発見してもらうのが普通です。

こちらも正しくリンクを実装していないとURLを検出してもらえない可能性があるので、リンクはa要素で実装しましょう。

またSPAに限った話ではないのですが、このようなケースでは[サイトマップ](https://support.google.com/webmasters/answer/183668?hl=ja)を用意してサイトのURLを知らせてあげることも有効だと思います。

## メタ情報の正しい設定

SEOや集客の観点から設定が必要だと思われる要素は、次のようなものが挙げられます。

- title
- meta description
- rel="canonical"
- 各種OGP(Open Graph Protocol)

いずれも、URLの示すページにあわせて設定していく必要があります。いくつか手段はあると思いますが、Reactの場合、[react-helmet](https://github.com/nfl/react-helmet)でページに合わせた設定が可能です。

### 重複コンテンツを防ぐための自己参照canonical

さまざまなパラメータを取り扱う可能性のあるSPAでは、フレームワークやライブラリののルーター設計により意図しないURLで閲覧できたり、重複コンテンツが発生してしまうリスクも高いように思います。こうした重複コンテンツの発生を防ぐには、自分自身のインデックスさせたいURLを rel="canonical"のパラメータに記述する自己参照canonicalで明示的に見せておくことも有効です。

## 今後気にするべき動向

日本では、キュレーションメディアの問題やこれに対応するアップデートが話題になっていますが、SEOの文脈でエンジニアが気にすべき話題はMFI(Mobile First Index)です。現在のところまだ正式に導入はされていないようですが、Googleからは以下のようなアナウンスがされています。

[Google ウェブマスター向け公式ブログ: モバイル ファースト インデックスに向けて](https://webmaster-ja.googleblog.com/2016/11/mobile-first-indexing.html)

個人的には、PC向けとSP向けで極端にサイトの作りが違うケースを除けばそこまで気を使う必要はないと考えていますが、今後の動向には注意していく必要があります。

# 当たり前のことを正しく実装する

長々と書きましたが、結局何をすればよいの？と思う方も多いと思います。

改めて並べると本当にあたりまえのことになってしまうのですが、個人的にはおおよそ以下の点に気をつければOKだと思っています。

- ステータスコードは正しく返す
- 可能ならできるだけSSRにする
- リンクはa要素で正しく記述する
- レガシーなサイトと同様にメタ情報を記述

基本的に、レガシーなWebサイトにおけるSEO向けの実装を同じようにSPAへ持ち込めれば問題は発生しないはずです。

## そもそも、Webサイト構築にSPAを採用するべきなのか？

SSRが可能なら、SPAだからといってSEOで不利になるということはありません。開発上の観点からは、APIを境界としてアプリケーションを分離することで、フルスタックなサーバサイドアプリケーションでサイト構築をするよりもクリアな設計が可能だと感じています。ユーザー視点では、差分データの取得のみでページ遷移・レンダリング可能なSPAは、特に通信環境の悪いモバイル環境においてUXの向上に寄与するはずです。

ただしSEOが特に重要なサイトの場合、SPAで実装するのはレガシーなWebサイトの実装に比べてやや気にするべき点も多く、本当にSPAを採用すべきかどうかは検討の余地があります。

実装コストやスキルレベル・サイトとして重視するKPIなどによって判断すべきだと思いますが、SPAでWebサイトを構築する際は、上記のようなことも気をつけるとよいのではないかと思います。