この記事は ベーシック アドベントカレンダー の12日目の記事です。
ベーシック開発部タインと申します。
WebSiteの初期表示を高速化するのはいつも重要なことですから、
今回は多様にある改善方法でProgressive Server Side Rendering(PSSR) の方法を紹介と試したいと思います。
PSSRとは
PSSRの概念を理解するためには、まずCSRとSSRの理解が必要となるのであります。
CSR
CSR、クライアントサイドレンダリングの略です。これはクライアントのブラウザで javascriptsの処理を行ってHTMLをレンダリングする方法です。
代表:React, Vue,...
- ブラウザからリクエストを送る
- サーバーがリクエストを処理してHTMLデータを返す
- ブラウザがJSダウンロードリクエストを作成する
- ブラウザがダウンロードされたJSを解析して、実行して、コンテンツをレンダリングする
メリット
- 柔軟性が高い
デメリット
- 初期表示速度が遅い
- SEOに弱い
- ブラウザの負荷がかかる
SSR
SSR、サーバーサイドレンダリングの略です。これはJavaScriptをサーバー内部で実行して、HTMLを生成することです。
代表:Next.js, Nuxt.js,...
- ブラウザからリクエストを送る
- サーバー内部でJavaScriptを実行して、HTMLを生成する
- ブラウザにそこのHTMLデータを渡す
- ブラウザがそこのデータをパースしてレンダリングする
メリット
- CSRより初期表示速度が早い
デメリット
- サーバー内部で重要じゃない部分も含めて全部HTMLをレンダリングしますので、初期表示速度まだ改善できる
PSSR
PSSR、プログレッシブサーバーサイドレンダリングの略です。この方法はサーバー内部で重要な部分だけ先にレンダリングして、ストリーム経由でブラウザにHTMLデータを渡します。そこでユーザーの体感速度も向上になります。
- ブラウザからリクエストを送る
- サーバー側は大切な部分を先に処理して、HTMLを生成して、ストリーム経由でブラウザにHTMLデータを渡す
- ブラウザがそこのデータをパースしてレンダリングする
- その後サーバー側は残り部分を引き続きブラウザにストリームする
- ブラウザが残りのデータをレンダリングする
PSSRはCSRとSSRのメリットを解決できるし、ユーザーの体験も改善できます。
SSR | PSSR |
---|---|
PSSRを実現してみる
環境
- MacOS Mojave
- Node v10.14.0
- Express v4.17.1
1.Nodeアップを作成する
$ npm init
Express
をインストール
$ npm install --save express
2. Patialを用意する
ページ全体のHTMLソースをpatialとして分けます。
<!-- views/1-openHTML.html -->
<html>
<!-- views/2-head.html -->
<head>
<style>
body {
height: 100vh;
margin: 0 100px;
}
</style>
</head>
<!-- views/3-openBody.html -->
<body>
<!-- views/4-header.html -->
<header>
</header>
<!-- views/5-main.html -->
<main>
</main>
..........
3. Patialの読み取りするモジュールを用意する
// src/renderer.js
module.exports = {
openHTML: async () =>
await loadHTML(__dirname + "/views/1-openHTML.html"),
head: async () =>
await loadHTML(__dirname + "/views/2-head.html"),
openBody: async () =>
await loadHTML(__dirname + "/views/3-openBody.html"),
header: async () =>
await loadHTML(__dirname + "/views/4-header.html"),
contentOpen: async () =>
await loadHTML(__dirname + "/views/5-contentOpen.html"),
sideLeft: async () =>
return await loadHTML(__dirname + "/views/6-sideLeft.html"),
main: async () =>
return await loadHTML(__dirname + "/views/7-main.html"),
sideRight: async () =>
return await loadHTML(__dirname + "/views/8-sideRight.html"),
.....
};
4. Readable APIでHTMLデータを渡す
// src/app.js
const app = express();
const renderer = require("./renderer");
// localhost:3000をアクセスする
app.get('/', async (req, res) => {
const openHTML = await renderer.openHTML();
const head = await renderer.head();
const openBody = await renderer.openBody();
res.write(openHTML);
res.write(head);
res.write(openBody);
// この順番でHTMLデータをストリームする
const dataStreams = [
renderer.header,
renderer.contentOpen,
renderer.main,
renderer.sideLeft,
renderer.sideRight,
renderer.contentClose,
renderer.footer,
renderer.closeBody,
renderer.closeHTML
];
// 読み取り可能なストリームを作成する
const readStream = new Readable({
async read(size) {
if (dataStreams.length) {
const dataStream = dataStreams.shift();
const dataStreamHTML = await dataStream();
readStream.push(dataStreamHTML);
} else {
readStream.push(null); //読み取り可能なデータがないと、ストリームをストップする
}
}
});
// pipe() メソッドは読み取り可能なストリーム(readStream)と書き込み可能なストリーム(res)を関連付けるもので、
// 後はデータを渡してくれる
readStream.pipe(res);
});
5. 試する
$ npm run start
Server running at http://127.0.0.1:3000/
まとめ
CSR: fast
SSR: faster
PSSR: more faster
???: fastest
今回の紹介したPSSRは静的なHTMLで試してみますが、ReactやVueなどもできると思います。
次のパーツはReact, VueでPSSRを試します。お待ちください