Server Side Renderingについて知るべきこと。Server Side Renderingとは何か? それによって何が改善されるのか?(前編) ng-japan 2017
JavaScriptフレームワークとして知られるAngularのイベント「ng-japan 2017」がAngular Japan User Group主催で6月17日に都内で開催されました。
Angularは基本的にWebブラウザで実行されるJavaScriptアプリケーションのフレームワークですが、一方でサーバサイドでAngularが備えるHTML構成機能を実現する、いわゆるServer Side Rendering機能の開発も「Angular Universal」として進んでいます。
そのため、Server Side Renderingに興味を持つAngularデベロッパーも増えてきました。
ng-japan 2017では、そうしたAngularデベロッパーのためのセッション「You need to Know SSR」が行われました。この記事では、その内容をダイジェストで紹介します。
You need to Know SSR
Node.js日本ユーザーグループの代表をやっています、Yosuke Furukawaと申します。
僕は普段、どちらかというとReact界わいの人ですが、先ほどちょっと魂を売ってきました。なのでみなさん仲間ということで優しくしてください(笑)
というわけで本題に入ります。
まずSever Side Renderingとはなにか、という話をします。
ブラウザの動きを見ると、図の左にあるブラウザからサーバへリクエストが出て、それがサーバへ到達すると、その裏にデータベースなどがあって、データベースから値をとってきたらコンポーネントやテンプレートエンジンなどを使ってHTMLにしてブラウザへ返す、という動きをしていると思います。
Ruby on RailsやJavaServer Pagesなどで作ったアプリケーションもこんな動きになると思います。これは普通のHTMLのレンダリングですよね。
で、最近はAngularもそうだしReactもそうなのですが、ブラウザの中にも、これまでサーバ側で動いていたHTMLを構築するための仕組みが入ってきています。
Serevr Side Renderingというときに、いろんな意味があるのですが、狭義の意味としては、HTMLを構築する仕組みがブラウザとサーバで共通のものが入ってきていて、それを共通のロジックを使って動かしましょう、というのがServer Side Renderingなんですね。
なぜServer Side Rendiringが必要なのか:SEO
なぜServer Side Renderingが必要なのかというといくつか理由がありますが、まず「SEO」が最初に挙がるのかなと。
今回はこれについて詳しくは話しませんが、Googleの中の人が、AngularやReactなどのJavaScriptフレームワークを使ったサイトでは、プリレンダリングつまりServer Side Renderingを推奨する、という記事が海外SEOに出ています。
これはなぜかというと、GoogleのクローラはJavaScriptを実行できるので、HTMLの中にコンテンツがなくても、JavaScriptの実行によってコンテンツが表示されるのであれば、それを読み込んでインデックス化してくれるはずなのですが、しかし100%完全にJavaScriptを実行してそのページを正しくレンダリングしてくれる保証はありませんと。
だからSEOをちゃんとしたいのであれば、Server Side Renderingをしましょうと。
なぜServer Side Renderingが必要なのか:パフォーマンスの改善
でも僕がServer Side Renderingをするいちばんの理由は、First View Performanceの改善です。
First View=初期表示といってもいろんな意味があるので、そこを無視してFirst View Performanceの改善と言ってもいろんな話が混ざってしまいます。そこで、まずFirst Viewについての説明を書いてきました。
まず「Navigation Start」はナビゲーションの開始で、それはサーバへリクエストが送られた段階ですね。
そしてサーバからデータが返ってきて、何かレンダリングが始まる。これが「First Paint」。
そこからローディングインジケータみたいなのがぐるぐる回るとか、たいして意味はないけれどコンテンツが表示される。これが「First Contentful Paint」。
その次の「First Meaningful Paint」で、意味のある情報が表示されるようになって、次の「Visually Ready」にいくと画像とかアセットと呼ばれるものが表示され、コンテンツが見やすくなっています。
次が「Time to interactive」。JavaScriptがロードされ実行されて、操作が可能になります。
最後が「Fully Loaded」で、「いいね」ボタンなどのソーシャルボタンなんかはだいたい最後に読み込まれることが多いと思いますが、そこまでコンテンツが全部揃ったものです。
じゃあServer Side RenderingにおけるFirst Viewのパフォーマンス改善とはどこを指すかというと、「Navigation Start」から「First Meaningful Paint」までです。
で、First Meaningful Paintから先の改善のやり方には、Service Workerを使うとかHTTP/2を使うとか、いろんなやり方があります。
なのでFirst View Performance全体の改善にはいろいろある、ということを覚えておいてください。
Server Side RenderingはCPU負荷が高い
First Contentful PaintとTime to Interactiveのタイミングがほとんど同じなのが、Client Side Renderingです。JavaScriptがロードされ実行されるとコンテンツが表示され、操作もできるようになります。
言い換えると、First Contetful PaintからFirst Meaningful Paintのあいだ、JavaScriptがロードされて実行されるまでの時間になるので、ここが若干長くなるのですね。
ここを問題視するか否かなんですが、僕は問題視しています。ユーザーは基本的にコンテンツが表示されてから操作することが多いので、First Meaningful PiaintとTime to Interactiveが全く一緒だと時間的に若干無駄がある。
ここはClient Side Renderingのみでは解決できないことかなと思います
そこでServer Side Renderingなわけです。
Server Side Renderingでは、初期データを埋め込んだHTMLをブラウザに送信するので、First Contentful PaintからFirst Meaningful Paintのあいだをすごく短縮できます。
じゃあServer Side Renderingをやりましょう、というと、話はそう簡単でもなかったりします。
Server Side Renderingにも課題はいくつかあって、サーバでHTMLを生成するのはCPU負荷が高い処理になるとか。
だいたいブラウザでのレンダリングエンジンはAngularやReactなどJavaScriptで動いていることが多いので、それをサーバで動かそうとするとNode.jsを使うことになります。
そして、これらをNode.jsを使おうとすると、メインループをブロックしてしまうことが多い。少なくとも現時点のReactではブロックすることが多いし、Angularもそのようです。
例えば、1回のリクエストに対して10%くらいのCPU負荷がかかるとしたら、同時に10リクエストまでしか処理できません。それ以上はサーバを増やすなりしないといけないのです。
Server Side Renderingをはじめてからサービスに人気が出てきたりすると、そのあたりに課題がでてきますね。
なぜCPU負荷が高いのかというと、これは弊社の同僚の吉田がまとめてくれたReactDOMSerer.renderToStringの処理についての資料なのですが、コンポーネントの中にコンポーネントがあって、その中にさらにまたコンポーネントがあるという再帰的な構造になっていて、それを毎回インスタンスを生成しながら、そのコンポーネントにIDを振らなくちゃいけないんですね。仮想DOMなので。
しかも最後にHTMLのチェックサムを作らなくてはいけない。そういう面倒な処理がたくさん含まれているのがReactのServer Side Renderingの処理のようです。
これはReactの例ですが、Angularでもこうした負荷の問題からは逃げ切れていません。
≫後編に続く。後編では、Server Side Renderingの課題であるCPU負荷をどうやって解決するか、現実解について解説されています。
あわせて読みたい
Server Side Renderingについて知るべきこと。Server Side Renderingとは何か? それによって何が改善されるのか?(後編) ng-japan 2017
≪前の記事
SlackがAmazon.comから買収の打診を受けた、との報道。Bloomberg