Cloud FunctionsでSSRして、OGPタグを動的に書き換える

概要

SPAで特定のページをTwitterやFacebookでシェアさせたい場合があると思います。
しかし、OGPの仕組み上、TwitterやFacebookのクローラーに対してmeta tagを表示させてあげる必要があり、クライアントサイドでの書き換えを行っても、これに反映させることはできません。

これを解決する方法としては、

  • ダイナミックレンダリングする

参考: ダイナミックレンダリングの使用方法
クローラーかどうかを判断し、クローラーの場合には用意してある静的なコンテンツを読み込ませる方法です。ブログなど、コンテンツの修正の頻度が小さいものであれば、私はこの方法を選択しています。
これによって、クローラー側ではJavascriptを実行する必要がなくなります。

  • SSR (サーバーサイドレンダリング)する

NextJsなどがフレームワークとして代表的ですが、サーバーサイドでコンテンツを形成してから、フロントエンドに返します。

  • Meta tagのみ、SSRする

今回の記事の対象です。
全てSSRほどの手間がかからず、OGP対策のみを考えているのであれば、これを選択するべきだと思っています。
ただし、アプリのユースケースによって、そこまで編集がされないコンテンツなのであれば、ダイナミックレンダリングを考えてもいいのかなと思います。

今回、バックエンド側はCloud Functionsでの実装が前提です。

実装の概要

ざっくりとやろうとしていることを図にしました。

Created with Sketch. SSRするURL Cloud Functions ① firebase.jsonのhostingを設定して、特 定のURLに対する挙動をカスタマイズする ② Botであれば、メタタグを書き換えたHtml をrenderし、それ以外はそのままRenderす る。 SSRしないURL /user/{userId} exports.returnHtmlWithOGP() /about /home OR

Cloud FunctionでSSRする

SSRの対象

正確に言うと、SSR時でメタタグの書き換えを行う対象ユーザーです。

今回は、以下のクローラー(Bot)であれば、書き換えを行うこととし、一般ユーザーからのアクセスに対しては書き換えを行いません。

その理由は、タグの書き換えのためにFirestoreなどのDBにアクセスし取得する負荷を減らすためです。

UserAgentから、botかどうかの判定をするコードは以下です。

Cloud Functionsにリクエストを送信する

次に、特定のURLにアクセスされた時に、Cloud Functionsにリクエストを送信するために、以下のようにfirebase.jsonを設定します。

リライトルールを使用すると、特定のパターンに一致するリクエストを単一の宛先に送ることができます。たとえば、Hosting サイトの /bigben ページからすべてのリクエストを送信して bigben 関数を実行するには、firebase.jsonを開き、hosting セクションの下に次の rewrite 構成を追加します。

参照: Cloud Functions による動的コンテンツの配信

Build時に、index.htmlをコピーしておく

フォルダ構成によりますが、Build後のタイミングで、Cloud Functionsから読み込める階層にindex.htmlをコピーするようにタスクを記述して上げることで、自動化します。

package.json

"build": "react-scripts build && cp build/index.html functions/hosting/"

Cloud Functionの実装

以下が完成したコードです。

処理の流れとしては、

① index.htmlを読み込み、Stringに変換する

② Bot(クローラー)でなければ、処理せずにindex.htmlを返す。Botであれば、DBから取得したデータを使い、正規表現で置換して、新規にindex.htmlを作成する

となっています。

注意点として、Cloud Function

Fetch as Googleしてみる

ここまででSPAでmeta tagを書き換え、クローラーに読み込ませることができました。

それでは、実際のページについてはどうでしょうか。

以下がFetch as Googleした結果で、Botからみたアプリなのですが、クライアントサイドで、読み込み中に表示させているgifが表示されています。

ダイナミックレンダリングや、全体のSSR化で解決できる問題ではあるのですが、フロント側で処理速度を上げてみた後に考えることなのかなと思って、今対応しています。

(追記)

Firebaseの各種サービスのロケーションを東京に変更して、パフォーマンスの向上をはかってみました。これで、サードパーティを含めホスティングされているリージョンが東京になりました。

結果として、Botからコンテンツの閲覧が可能になりました!

やはり、パフォーマンスをあげるというアプローチがまず取り組むことなのかなと実感した次第です。

参照: Firebaseで東京リージョンに移動する手順

Before

パフォーマンス改善前のGoogle Botからの見え方

After

after
パフォーマンス改善後のGoogle Botからの見え方