Reactアプリを人生で初めて速くしてみる
動機
第7回Ginza.jsに参加した時にmottox2さんのLTでServer Side Renderingの文脈でPre-renderingの話が出ました。
「アプリケーションを作る」という経験はあるものの、最適化・高速化するという経験はなかったので、なんか面白そうだしやってみようと思いました。
#ginzajs から何か一つ持って帰りたいので、自分で作ったReactアプリでPre-renderingしてみてPageSpeed Insightsのスコアどんだけ改善できるかやってみる
— 金子幸三郎 (@Kosaburo_Kaneko) 2019年12月9日
Pre-renderingとはなんぞや
Googleで検索するとトップに出てきたので僕の適当な説明よりもこちらを参考にしてもらえればと思いますが、
https://greative.jp/page/guidebook-spa-ssss-1/
僕の理解だとPre-renderingは「ビルド時にアプリの初期状態のHTMLをレンダリングしておいて、リクエストがあったらまずそれをレスポンスで返す」ということだと認識してます。
なので通常SPAだとクライアント側でJavaScriptがHTMLをレンダリングし始めるので時間がかかるけど、とりあえず目に見えるHTMLが最初に返ってくるからユーザーから見るとレスポンスが速く感じるというメリットがあります。
Pre-renderingしてみた
構成
Reactアプリケーションをビルドして生成された静的ファイルをnginxが返しています。
react-snapshot
LTでも紹介があったこのライブラリを使ってみました。
使い方はとても簡単で、まずこのライブラリをインストールしてください。
インストールし終わったらReactDOMがレンダリングしているところをreact-snapshotに任せてください。
@@ -1,5 +1,5 @@ | ||
import * as React from 'react'; | ||
import * as ReactDOM from 'react-dom'; | ||
const { render } = require('react-snapshot'); | ||
import App from './App'; | ||
import { Provider } from 'react-redux'; | ||
@@ -14,7 +14,7 @@ const store = createStore<SNSAccountState, any, any, any>( | ||
composeWithDevTools() | ||
); | ||
ReactDOM.render( | ||
render( | ||
<Provider store={store}> | ||
<App /> | ||
</Provider>, |
次にpackage.jsonのscripts部分を以下のように書き換えます。
"build": "node scripts/build.js", | ||
"build": "node scripts/build.js && react-snapshot", |
これでビルド時にPre-renderingが自動で行われ、ページのスナップショットが作成されます。
もともとあったindex.htmlは200.htmlに転生し、ビルド時に撮られたスナップショットが新しいindex.htmlを担当します。リクエストされたURLのスナップショットがあればindex.htmlが呼ばれますが、もし存在しない場合は200.htmlが返されます。
これだけでPre-renderingされたスナップショットが返るようになるってすごい。
PageSpeed Insightsの改善
もともとのスコアはこんな感じです。
モバイル改善前
PC改善前
いや、スコアが低いのはわざとですよ?わざと。
じゃないとどれくらい改善されたかわかりづらいじゃないですか。
やだなあ。
モバイルの12ってなんなんだよマジで...
では、Pre-renderingを導入した結果を見てみましょう。
モバイル改善後
改善前12 → 改善後13
え、1しか上がってない...
PC改善後
改善前70 → 改善後67
なんか下がってるんですけどwwwwww
Pre-rendering自体はPageSpeed Insightsのスコアには影響をあまり与えないのかもしれないです。ただ体感的にはファーストページローディングはけっこう速くなったように感じますし、効果は確実にあったと思います。
gzipでスコア上げる
「基本中の基本だろ」と言われるかもしれないですが、ビルドされたファイルをgzipで圧縮するようにしました。
compression-webpack-plugin
圧縮する方法はいくつかあると思いますが、今回このライブラリを導入することにしました。
使い方はwebpackのconfigのpluginに追加するだけです。このライブラリを使うとgzipで圧縮したものとしてないものの両方がビルドされます。通常の設定だとgzipで圧縮してない方が返されてしまうので、圧縮した方を返すように一緒にnginx.confの設定も変更しました。
これでgzipで圧縮されたものが先に呼ばれ、もし圧縮されたものがなかったら今まで通りのファイルが呼ばれるようになります。
モバイル改善 + 圧縮後
PC改善 + 圧縮後
だいぶ改善しました。特にPCは緑色になってくれてよかったです。
終わり
LTを見に行ったことで新しいことにチャレンジできたので、また行きたいなと思いました。