最近流行りのreactやvueなどSPAでWebアプリを作ると、サーバサイドレンダリング(SSR)をすべきか悩みます。
Googleのクローラはjavascriptを割ときちんとレンダリングしてくれるため、あまり意識なくてもいいようになりました。
一方、titleやogpなどのmetaタグをjavascriptで書き換えている場合、twitterやslackで共有した際にカードが正しく表示されない問題は依然残されています。
metaタグだけをサーバサイドレンダリングすることも可能ですが、今回は prerender.io を使い、クローラに向けてだけレンダリング済みのHTMLを返すようにしたいと思います。
javascriptをレンダリングし、javascriptタグを除いた素のHTMLをキャッシュしてくれるサービスです。
googleやtwitter等のクローラをオリジナルではなく prerender.io の方に転送することで、レンダリング済みのHTMLをクローラに渡すことができます。
例えば、このサイトのトップページをprerenderした結果は以下のようになります。
proxyの設定がされていないので、相対パスで設定されている画像やstyleが表示されていませんが、実際に使用する際は設定するので画像等も正しくクローラに渡せます。
クローラを判別して転送する方法は、以下のようにNginxやApacheで行う方法に、ExpressJS、Rails、Spring等にミドルウェアを導入する方法などがあります。
server {
listen 80;
server_name example.com;
root /path/to/your/root;
index index.html;
location / {
try_files $uri @prerender;
}
location @prerender {
#proxy_set_header X-Prerender-Token YOUR_TOKEN;
set $prerender 0;
if ($http_user_agent ~* "googlebot|bingbot|yandex|baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
set $prerender 1;
}
if ($args ~ "_escaped_fragment_") {
set $prerender 1;
}
if ($http_user_agent ~ "Prerender") {
set $prerender 0;
}
if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
set $prerender 0;
}
#resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
resolver 8.8.8.8;
if ($prerender = 1) {
#setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing
set $prerender "service.prerender.io";
rewrite .* /$scheme://$host$request_uri? break;
proxy_pass http://$prerender;
}
if ($prerender = 0) {
rewrite .* /index.html break;
}
}
今回はAWSのS3に置いたjavascriptをCloudFrontで配信しているケースを想定して行います。(このサイトはそのように構築されています。)
レンダリングはprerender.ioに行ってもらうため、ここ から登録を行ってください。
そしたら後で使うので アカウント情報 からtokenをメモっておきます。
全体像は以下のようになります。
S3に配置したhtml、javascriptをCloudFrontを経由して配信しており、2つのLambdaでクローラを判別、 prerender.io に転送しています。
少し複雑な仕組みですが、簡単に構築できるスクリプトが公開されています。
Cloudformation を開き、スタックの作成を開始します。
このときに、日本regionではなく、バージニア北部を選択するように気をつけてください。(Edgeが起動できなくてエラーが出ます。)
上のリポジトリから prerender-cloudfront.yaml
をダウンロードしてきて、アップロードします。
そしたら、次の画面に表示される PrerenderToken
に先程prerender.ioで発行したtokenを入力します。
あとは作成を押すだけで、CloudFront、S3、Edge全てが作成されます。
S3に自分のindex.htmlと、js、css、画像等をアップロードすれば、すぐにWebページが公開されます。
実際にprerenderされているか、コマンドで確かめることができます。
curl -H 'User-Agent: Facebot' https://${CLOUDFRONT_DOMAIN}
また、prerender.io でもどのページがキャッシュされているのか確認することができます。
AWSでも簡単にprerender.ioを設定して、botにレンダリング済みのHTMLを渡すことができました。
SPAに関してはいろいろな意見がありますが、僕個人としてはクローラーがjavascriptエンジンを持ち、今後SSRしなくてもよくなると思っています。
それまでの間、このような応急処置もありなのではないでしょうか。