2019 年 1 月 31 日(木曜日)
多くのフロントエンド フレームワークは、コンテンツの表示に JavaScript を使用しています。そのため、Google がコンテンツをインデックスに登録する、またはインデックスに登録されたコンテンツを更新する際に時間を要する場合があります。
今年の Google I/O で議論した回避策は、ダイナミック レンダリングです。ダイナミック レンダリングを実装する方法は多数存在します。このブログ投稿では、Rendertron を使用したダイナミック レンダリングの実装例を紹介します。Rendertron は headless Chromium をベースとしたオープンソース ソリューションです。
ダイナミック レンダリングを検討すべきサイト
サイトにアクセスする検索エンジンやソーシャル メディアの bot が、すべて JavaScript を実行できるわけではありません。Googlebot が JavaScript を実行するには時間を要し、こちらに示すようないくつかの制限が存在します。
ダイナミック レンダリングは、変更頻度が高く、表示に JavaScript を必要とするコンテンツに対して有用です。ハイブリッド レンダリング(Angular Universal など)を検討することで、サイトのユーザー エクスペリエンス(特に First Meaningful Paint までに要する時間)を向上できる可能性があります。
ダイナミック レンダリングの仕組み
ダイナミック レンダリングとは、特定のユーザー エージェントを対象に、クライアント側でレンダリングされるコンテンツとプリレンダリングされるコンテンツを切り替えることを指します。
JavaScript を実行して静的 HTML を生成するにはレンダラが必要です。Rendertron は、ヘッドレス Chromium を使用してレンダリングするオープンソース プロジェクトです。シングルページ アプリでは、バックグラウンドでデータを読み込んだり、コンテンツをレンダリングする工程を後回しにしたりすることがよくあります。Rendertron には、ウェブサイトでレンダリングが完了したタイミングを判定するメカニズムがあります。Rendertron は、すべてのネットワーク リクエストが完了し、未処理の作業がなくなるまで待機します。
このブログ投稿で扱う内容
- サンプルのウェブアプリを確認する
- 小規模な
express.js
サーバーを設定してウェブアプリを配信する - ダイナミック レンダリング用のミドルウェアとして Rendertron をインストールして構成する
サンプルのウェブアプリ
「kitten corner」ウェブアプリは、JavaScript を使用して、さまざまな猫の画像を API から読み込み、グリッド形式で表示します。
以下がこのウェブアプリの JavaScript です。
const apiUrl = 'https://api.thecatapi.com/v1/images/search?limit=50'; const tpl = document.querySelector('template').content; const container = document.querySelector('ul'); function init () { fetch(apiUrl) .then(response => response.json()) .then(cats => { container.innerHTML = ''; cats .map(cat => { const li = document.importNode(tpl, true); li.querySelector('img').src = cat.url; return li; }).forEach(li => container.appendChild(li)); }) } init(); document.querySelector('button').addEventListener('click', init);
このウェブアプリでは、Googlebot ではまだサポートされていない最新の JavaScript(ES6)が使用されています。モバイル フレンドリー テストを使用して、Googlebot がコンテンツを認識できるかどうかを確認できます。
この問題は簡単に修正できます。こうした修正は、ダイナミック レンダリングを設定する方法を学習するための良い練習となるでしょう。ダイナミック レンダリングにより、ウェブアプリのコードを変更せずに Googlebot に猫の画像を認識させることができます。
サーバーの設定
ウェブアプリを配信するために、node.js
ライブラリの express
を使用してウェブサーバーを構築します。
サーバーコードは次のようになります(プロジェクトのフル ソースコードをご覧ください)。
const express = require('express'); const app = express(); const DIST_FOLDER = process.cwd() + '/docs'; const PORT = process.env.PORT || 8080; // Serve static assets (images, css, etc.) app.get('*.*', express.static(DIST_FOLDER)); // Point all other URLs to index.html for our single page app app.get('*', (req, res) => { res.sendFile(DIST_FOLDER + '/index.html'); }); // Start Express Server app.listen(PORT, () => { console.log(`Node Express server listening on https://localhost:${PORT} from ${DIST_FOLDER}`); });
ライブサンプルを試すことができます。最新のブラウザを使用している場合は、たくさんの猫の画像が表示されます。パソコンからプロジェクトを実行するには、node.js
で次のコマンドを実行する必要があります。
npm install --save express rendertron-middleware node server.js
次に、ブラウザで https://localhost:8080
を指定します。ここからはダイナミック レンダリングを設定します。
Rendertron インスタンスのデプロイ
Rendertron は、URL を取得し、ヘッドレスの Chromium を使用してその URL の静的 HTML を返すサーバーを実行します。Rendertron プロジェクトの推奨事項に沿って、Google Cloud Platform を使用します。
支払いを必要とせず利用できる使用量ティアで開始できます。本番環境でこのセットアップを使用すると、Google Cloud Platform の料金に基づいて課金が発生する可能性があります。
- Google Cloud コンソールで新しいプロジェクトを作成します。入力フィールドの下の「プロジェクト ID」をメモします。
- ドキュメントの手順に沿って Google Cloud SDK をインストールし、ログインします。
-
以下のコマンドで、GitHub にある Rendertron リポジトリのクローンを作成します。
git clone https://github.com/GoogleChrome/rendertron.git cd rendertron
-
次のコマンドを実行して依存関係をインストールし、パソコンに Rendertron を構築します。
npm install && npm run build
-
rendertron ディレクトリに
config.json
という新しいファイルを次の内容で作成して、Rendertron のキャッシュを有効にします。{ "datastoreCache": true }
-
rendertron ディレクトリから次のコマンドを実行します。
YOUR_PROJECT_ID
は、ステップ 1 のプロジェクト ID に置き換えます。gcloud app deploy app.yaml --project YOUR_PROJECT_ID
- 任意のリージョンを選択して、デプロイを確定します。デプロイが完了するまで待ちます。
YOUR_PROJECT_ID.appspot.com
URL を入力します。入力フィールドといくつかのボタンがある Rendertron のインターフェースが表示されます。
Rendertron ウェブ インターフェースが表示されたら、Rendertron インスタンスが正常にデプロイされています。プロセスの次の部分で必要になるため、プロジェクトの URL(YOUR_PROJECT_ID.appspot.com
)をメモしておきます。
サーバーへの Rendertron の追加
ウェブサーバーは express.js
を使用しており、Rendertron には express.js
ミドルウェアがあります。server.js
ファイルのディレクトリで、次のコマンドを実行します。
npm install --save rendertron-middleware
このコマンドにより、npm から rendertron-middleware がインストールされます。これで、rendertron-middleware をサーバーに追加できます。
const express = require('express'); const app = express(); const rendertron = require('rendertron-middleware');
bot リストの構成
Rendertron は、user-agent
HTTP ヘッダーを使用して、リクエストが bot とユーザーのブラウザのどちらから発信されているかを判別します。最新状態に維持された bot のユーザー エージェントのリストを備えており、このリストと比較します。Googlebot は JavaScript を実行できるため、デフォルトではこのリストに Googlebot は含まれません。Rendertron に Googlebot リクエストもレンダリングさせるには、ユーザー エージェントのリストに Googlebot を追加します。
const BOTS = rendertron.botUserAgents.concat('googlebot'); const BOT_UA_PATTERN = new RegExp(BOTS.join('|'), 'i');
Rendertron は、後で user-agent
ヘッダーとこの正規表現を比較します。
ミドルウェアの追加
bot リクエストを Rendertron インスタンスに送信するには、express.js
サーバーにミドルウェアを追加する必要があります。ミドルウェアはリクエストしているユーザー エージェントを確認し、既知の bot からのリクエストを Rendertron インスタンスに転送します。次のコードを server.js に追加します。必ず YOUR_PROJECT_ID
を Google Cloud Platform のプロジェクト ID に置き換えてください。
app.use(rendertron.makeMiddleware({ proxyUrl: 'https://YOUR_PROJECT_ID.appspot.com/render', userAgentPattern: BOT_UA_PATTERN }));
サンプル ウェブサイトをリクエストする bot は Rendertron から静的 HTML を受け取るため、コンテンツを表示するために JavaScript を実行する必要がありません。
設定のテスト
Rendertron の設定に成功したかどうかをテストするには、もう一度モバイル フレンドリー テストを実行します。
最初のテストとは違い、猫の画像が表示されます。HTML タブには、JavaScript コードが生成したすべての HTML が表示され、コンテンツを表示するための JavaScript が Rendertron によって不要になったことがわかります。
まとめ
ウェブアプリに変更を加えずにダイナミック レンダリングを設定しました。この変更により、ウェブアプリの静的 HTML バージョンをクローラに提供できるようになります。