Reactアプリを人生で初めて速くしてみる

f:id:b1840943:20191217002120p:plain

 

動機

第7回Ginza.jsに参加した時にmottox2さんのLTでServer Side Renderingの文脈でPre-renderingの話が出ました。

「アプリケーションを作る」という経験はあるものの、最適化・高速化するという経験はなかったので、なんか面白そうだしやってみようと思いました。

 

 

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でも紹介があったこのライブラリを使ってみました。

 

github.com

 

使い方はとても簡単で、まずこのライブラリをインストールしてください。

 

インストールし終わったら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の改善

もともとのスコアはこんな感じです。

 

モバイル改善前

f:id:b1840943:20191214120434p:plain

PC改善前

f:id:b1840943:20191214120450p:plain

 

いや、スコアが低いのはわざとですよ?わざと。

 

じゃないとどれくらい改善されたかわかりづらいじゃないですか。

やだなあ。

 

モバイルの12ってなんなんだよマジで...

 

では、Pre-renderingを導入した結果を見てみましょう。

 

モバイル改善後

f:id:b1840943:20191214120817p:plain

改善前12 → 改善後13

 

え、1しか上がってない...

 

PC改善後

f:id:b1840943:20191214120855p:plain

改善前70 → 改善後67

 

なんか下がってるんですけどwwwwww

 

Pre-rendering自体はPageSpeed Insightsのスコアには影響をあまり与えないのかもしれないです。ただ体感的にはファーストページローディングはけっこう速くなったように感じますし、効果は確実にあったと思います。

 

gzipでスコア上げる

「基本中の基本だろ」と言われるかもしれないですが、ビルドされたファイルをgzipで圧縮するようにしました。

 

compression-webpack-plugin

圧縮する方法はいくつかあると思いますが、今回このライブラリを導入することにしました。

 

github.com

 

使い方はwebpackのconfigのpluginに追加するだけです。このライブラリを使うとgzipで圧縮したものとしてないものの両方がビルドされます。通常の設定だとgzipで圧縮してない方が返されてしまうので、圧縮した方を返すように一緒にnginx.confの設定も変更しました。

 

server {
  gzip on;
  gzip_static on;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_proxied  any;
  gzip_vary on;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
}

 

これでgzipで圧縮されたものが先に呼ばれ、もし圧縮されたものがなかったら今まで通りのファイルが呼ばれるようになります。

 

モバイル改善 + 圧縮後

f:id:b1840943:20191216234648p:plain

 

PC改善 + 圧縮後

f:id:b1840943:20191216234712p:plain

 

だいぶ改善しました。特にPCは緑色になってくれてよかったです。
 

終わり

LTを見に行ったことで新しいことにチャレンジできたので、また行きたいなと思いました。