サーバーサイド レンダリングではなく、React サイトのパフォーマンスを高速化したい場合は、プリレンダリングをお試しください。
react-snap
は、サイト上のページを静的 HTML ファイルにプリレンダリングするサードパーティ ライブラリです。これにより、アプリケーションの最初のペイント時間が短縮されます。
シミュレートされた 3G 接続とモバイル デバイスに事前レンダリングを読み込んだ場合と読み込まなかった場合の、同じアプリの比較を次に示します。
なぜこれが有用なのでしょうか。
大規模なシングルページ アプリケーションの主なパフォーマンスの問題は、サイトを構成する JavaScript バンドルのダウンロードが完了するまで、ユーザーが実際のコンテンツを表示できないことです。バンドルが大きいほど、ユーザーは長く待たされることになります。
これを解決するために、多くのデベロッパーは、ブラウザで起動するだけでなく、サーバー上でアプリケーションをレンダリングするアプローチを採用しています。ページまたはルートの遷移ごとに、HTML 全体がサーバーで生成され、ブラウザに送信されます。これにより、最初の描画時間が短縮されますが、最初のバイトまでの時間が遅くなります。
プリレンダリングは、サーバー レンダリングよりも複雑ではありませんが、アプリケーションの First Paint 時間を短縮する方法も提供します。ヘッドレス ブラウザ(ユーザー インターフェースのないブラウザ)を使用して、ビルド時にすべてのルートの静的 HTML ファイルを生成します。これらのファイルは、アプリに必要な JavaScript バンドルと共に配布できます。
react-snap
react-snap
は、Puppeteer を使用して、アプリケーション内の異なるルートのプリレンダリングされた HTML ファイルを作成します。まず、開発の依存関係としてインストールします。
npm install --save-dev react-snap
次に、package.json
に postbuild
スクリプトを追加します。
"scripts": {
//...
"postbuild": "react-snap"
}
これにより、アプリケーションの新しいビルドが作成されるたびに(npm build
)、react-snap
コマンドが自動的に実行されます。
最後に、アプリケーションの起動方法を変更する必要があります。src/index.js
ファイルを次のように変更します。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
ReactDOM.hydrate(<App />, rootElement);
} else {
ReactDOM.render(<App />, rootElement);
}
ReactDOM.render
を使用してルート React 要素を DOM に直接レンダリングするのではなく、子ノードがすでに存在するかどうかをチェックし、HTML コンテンツがプリレンダリングされた(またはサーバーでレンダリングされた)かどうかを判断します。その場合は、ReactDOM.hydrate
を使用して、すでに作成されている HTML にイベント リスナーをアタッチします。
アプリケーションをビルドすると、クロールされるルートごとにペイロードとして静的 HTML ファイルが生成されます。HTML リクエストの URL をクリックし、Chrome DevTools の [プレビュー] タブをクリックすると、HTML ペイロードを確認できます。
スタイル設定されていないコンテンツのフラッシュ
静的 HTML はほぼ瞬時にレンダリングされるようになりましたが、デフォルトではスタイルが適用されないままであるため、「スタイルなしコンテンツのフラッシュ」(FOUC) が表示される問題が発生する可能性があります。これは、CSS-in-JS ライブラリを使用してセレクタを生成している場合に特に顕著です。スタイルを適用するには、JavaScript バンドルの実行が完了する必要があります。
これを回避するには、クリティカル CSS(最初のページのレンダリングに必要な最小限の CSS)を HTML ドキュメントの <head>
に直接インライン化します。react-snap
は、別のサードパーティ ライブラリ(minimalcss
)を使用して、さまざまなルート用の重要な CSS を抽出します。これを有効にするには、package.json
ファイルで次のように指定します。
"reactSnap": {
"inlineCss": true
}
Chrome DevTools のレスポンス プレビューを見ると、重要な CSS がインライン化されたスタイル付きページが表示されています。
まとめ
アプリケーションにサーバー側のレンダリング ルートを使用しない場合は、react-snap
を使用して静的 HTML をユーザーに事前レンダリングします。
- これを開発環境の依存関係としてインストールし、デフォルト設定をそのまま使用します。
- 試験運用版の
inlineCss
オプションを使用して、サイトで機能する場合は重要な CSS をインライン化します。 - ルート内のコンポーネント レベルでコード分割を使用している場合は、読み込み状態をユーザーにプリレンダリングしないように注意してください。詳しくは、
react-snap
README をご覧ください。