フロントエンド周りをいじっていると、SSR(Server Side Rendering)やSPA(Single Page Application)などの技術が耳に入ってくることもあるでしょう。
SSRとは、スマホゲームのガチャじゃないですよ(笑)
SSRを一言で言うと「サーバーサイドでHTMLを生成して描画する」技術です。以下の画像を見ていただくとイメージしやすいと思います。
Webは従来、クライアントサイド(HTMLやCSS、JavaScript)とサーバーサイド(PHPやRuby、Goなど)と分けられます。
しかし、SSRでは、このクライアントサイドのページを表示する機能もサーバーサイドに持たせてしまおうということなのです。
この記事では、SSRの何が嬉しいのか?やSSRの具体例などを紹介していきます。
Server Side Renderingのメリット
サーバーサイドレンダリングのメリットは大きく2つあります。
- SPAなどの初回ページの表示速度を高速化できる
- TwitterやFacebookなどのシェアに対応できる
SSRのメリット:SPAの初回ページの表示高速化
SPA(Single Page Application)とは、「JavaScriptでページ内のHTMLを差し替えてコンテンツを切り替える」技術です。ページ遷移をするときなどは表示速度が速いのですが、最初にページを表示するときには時間がかかってしまうのがデメリットです。
SSRではこのSPAのデメリットをカバーできます。
少しSPAについて紹介します。
SPAでは最初の表示時に、
「空のHTML表示」+「JavaScriptの表示」
を行います。そしてページ遷移をするときに、ページ間で変更がある部分だけをサーバーに要求します。
通常はヘッダーやフッターなどの共通部分のデータもサーバーに取りに行っていますが、SPAではそれがない分ページ遷移では表示速度が速くなるのです。
一方、JavaScriptのコード量は増加するので、最初にページを表示するときには通常よりも時間がかかります。
しかしSSRでは、最初にページにアクセスした時点で、サーバー側でデータを整形した状態のHTMLを返すため初期ページの表示を高速化できるというわけなのです。
SSRのメリット:TwitterやFacebookのシェアに対応できる
従来のSPAではTwitterやFacebookなどでシェアされたときに表示される画像やタイトルの情報(OGPタグ)を表示することは基本的にはできません。
というのも、SPAでは空のHTMLが初期ロードの時点では返されるためURLをシェアしてもOGPタグの中身が空っぽになってしまうためです。
SSRでは、初期表示の時点できちんとデータが挿入されたHTMLを返すため、Twitterなどのシェアにも対応できるのです。
Server Side Renderingのサンプル
ここまでサーバーサイドレンダリングの概要をざっと説明しましたが、実際にコードを見ながらどのような技術なのか見ていきましょう。
今回、用意したのはシンプルなクリックをされるたびに数字がカウントされるというアプリケーションです。
具体的なソースを見てみましょう。
const express = require('express');
const http = require('http');
const _ = require('lodash');
const app = express();
let count = 0;
const countTemplate = `<%= count %>`;
const template = `
<div>
こんにちは、あなたは<span id='count'>${countTemplate}</span>番目のお客様です。
</div>
<button id='button'>count up</button>
<script>
const countCompiled = ${_.template(countTemplate)};
document.getElementById('button').addEventListener('click', () => {
const req = new XMLHttpRequest();
req.onload = (e) => {
const count = document.getElementById('count');
const result = JSON.parse(e.target.response);
count.innerHTML = countCompiled(result);
};
req.open('GET', '/api/count');
req.send();
});
</script>
`;
const compiled = _.template(template);
app.use('/api/count', (req, res, next) => {
res.json({ count: count++ });
});
app.use((req, res, next) => {
http.get({
port: 3000,
path: '/api/count'
}, (response) => {
let data = '';
response.on('readable', () => {
const chunk = response.read();
if (chunk) {
console.log(chunk.toString());
data += chunk;
console.log(data);
}
});
response.on('end', () => {
res.send(compiled(JSON.parse(data)));
})
})
});
app.listen(3000);
サーバーサイドのAPI処理をするためのライブラリとしてexpressというライブラリを使っています。
一度目のアクセスの際には、最終的に50行目のようにHTMLソースが書かれたtemplateを表示しています。
また、サーバーサイドレンダリングでHTMLソースを保持することにより、フロントエンドでcountのような変数を持つことも簡単に行えます。
今回のケースでは、ボタンがclickされた際にクライアントサイドでHTTPリクエストが行われ、ページの全部ではなく一部だけ更新するといった処理も加えています。
こちらはサーバーサイドレンダリングの直接的な恩恵ではありませんが、こういったメリットもあることは覚えておくといいかもしれません。