この記事はデベロッパー アドボケート、Ben Morss による Accelerated Mobile Pages Project の記事 "The Shadow Reader, Improved" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

Shadow Reader がさらに高速になり、検索エンジンとの親和性も向上しました!

Shadow Reader は、プログレッシブ ウェブアプリ(PWA)に AMP ページを組み込んだデモサイトです(詳細については、発表時の投稿をご覧ください)。このサイトは、The Guardian の記事を再利用して、没入感のあるニュース リーダー体験を提供しています。また、単なるデモにとどまらず、完成形のサイトとしてつくられています。AMP と PWA を効果的に組み合わせるために必要なコードはすべて含まれていて、本番環境でも十分に使用できます!

JS で生成されるコンテンツの SEO


Shadow Reader は典型的なシングルページ アプリケーションで、PWA においてユーザー体験が最適化される App Shell というパターンを採用しています。つまり、最初に取得するページ本体の HTML は小さく、App Shell として即時に読み込まれて、JavaScript でメイン コンテンツを読み込んでいる間に表示しておく外郭とプレースホルダーを用意しています。

ただし、このパターンは検索エンジンを困らせることにもつながります。Google 検索では、ページの完成形をインデックスするために、ページ本体の HTML を読むだけでなく、JavaScript の実行も試みますが、多くの検索エンジンでは JavaScript は実行されないか、確実に実行されるという保証はありません。言い換えれば、JavaScript の確実な実行を検索エンジン任せにするのは安全ではないということです。検索エンジンが 、ほとんどのコンテンツを読み込まずに App Shell だけを認識した場合、ページが正しくインデックスされることはありません。

そこで、たとえば Shadow Reader の記事テキストを、ページ本体の HTML に含めて検索エンジンに渡せたらどうでしょう?また、それによってページのレンダリングが遅くなることはなく、逆に新規ユーザーに対しては 1 秒以内にページを表示できるようになったらどうでしょう?すばらしいと思いませんか!

今回は、新規ユーザーに AMP 版の記事を配信することで、この両方を実現しました! ウェブ クローラーは新規ユーザーとしてサーバーに認識される点をうまく利用しています。では具体的に何をしたのか見ていきましょう。

AMP⇒PWA


今回は、AMP⇒PWA パターンを使ってこの検索エンジン対策を実装しました。

新規ユーザーに対しては :
  • 新規ユーザーが記事ページにアクセスしたときに、AMP 版のページを返します。
  • AMP は、<amp-install-serviceworker> を使って Service Worker を読み込み、インストールします。
  • Service Worker は App Shell を読み込み、キャッシュします。
  • 以降、画面遷移が発生する際には、Service Worker がすべてを制御することとなります。次ページ遷移時には App Shell を利用して PWA に移り変わるというわけです。

既存のユーザーに対しては : 単純に PWA の App Shell をそのまま使います。既存ユーザーには Service Worker がインストールされているので、Service Worker が画面遷移 を認識すると、キャッシュされている App Shell が利用されます。このように Service Worker を使うことによって、同じ URL にアクセスする場合でも、新規ユーザーと既存ユーザーを別々に扱うことができます。

では、この仕組みは Shadow Reader では実際にどのように動作するのでしょうか。 たとえばユーザーが次の記事ページに初めてアクセスした場合を考えてみましょう。
https://amp.cards/theguardian/us/amazing_article


サーバーは、新規ユーザーなので記事の URL を認識して AMP 版のページを返します。そして、記事が読み込まれる際に、Service Worker がインストールされます。Service Worker は、Workbox ライブラリを使用しており、次の一行が含まれています。
workboxSW.router.registerNavigationRoute('index.html')


これで、ユーザーがそのドメイン内で画面遷移するたびに、Service Worker がその画面遷移リクエストをインターセプトできるようになります。Service Worker はそのリクエストをサーバーに渡すのではなく、キャッシュされている index.html、すなわち PWA の App Shell を返します。

従って、次にユーザーが以下のリンクをクリックした場合、
https://amp.cards/theguardian/us/another_article


ブラウザに表示される URL は変わりつつも、Service Worker がキャッシュしている App Shell の HTML が読み込まれます。その後、JavaScript が実行され、URL をヒントに正しい記事コンテンツを読み込みます。このように既存ユーザーの場合は、すでにインストールされている Service Worker を利用して、キャッシュ済の PWA を使い続けることができます。

一方で、ウェブ クローラーは Service Worker をインストールしないため、必ず新規ユーザーとして AMP の記事が読み込まれます。

以上の手順をわかりやすい図にまとめます。


新規ユーザーに対しては :
  1. ブラウザが、サーバーに対して記事の URL をリクエストします。サーバーは、<amp-install-serviceworker> を含む AMP 版の記事を返します。 
  2. <amp-install-serviceworker> は、Service Worker JS をサーバーにリクエストします。サーバーは、ブラウザに Service Worker JS を返します。ブラウザは、Service Worker をインストールして起動します。 
  3. Service Worker は、インストール時に PWA App Shell をサーバーにリクエストします。サーバーは、リクエストされたリソースを Service Worker に返し、Service Worker はそれをキャッシュします。

既存ユーザーに対しては :
  1. ブラウザが、記事の URL をリクエストします。このリクエストを、Service Worker がインターセプトします。Service Worker は、キャッシュされている PWA をブラウザに返します。 
  2. PWA が AMP 記事をリクエストします。サーバーは AMP 記事を PWA に返します。PWA が処理し、記事を表示します。
ウェブ クローラーは常に新規ユーザーとして扱われる点にご注意ください!

次のステップ


今回の対応ができたところで、今後は Shadow Reader を以下のように改善していく予定です。
  • YQL ではなく、直接 Guardian の RSS フィードを利用する。 
  • 新規ユーザーに対して AMP ページを返す際に、トップ ナビゲーション リンクを Shadow Reader のリンクに変更する。
  • AMP Cache から配信されたことを考慮して、<amp-install-serviceworker data-iframe-src=”https://amp.cards/index.html“> と指定して Service Worker のインストールを実施しているが、今の実装だと Shadow Reader そのものをすべて読み込むようになっているので、もう少し軽量な Service Worker だけをインストールする HTML を指定するように変更する。
  • Backend.js は独自の実装でサーバーサイドでもフロントエンドでも動作するように作られているが、今後はリファクタリングも兼ねて ECMAScript モジュール で読み込ませるようにする。

ぜひ Shadow Reader をお試ししただき、Github のコードをチェックして、感想をお知らせください! 皆さんのサイトでどのように AMP/PWA を利用しているか教えてほしいですし、Shadow Reader の改善案もお待ちしています。


Reviewed by Yusuke Utsunomiya - Mobile Solution Consultant, gTech