サーバーサイド レンダリングではなく、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"
}
これにより、アプリケーションの新しいビルドが作成されるたびに react-snap
コマンドが自動的に実行されます(npm build
)。
最後に、アプリケーションの起動方法を変更する必要があります。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 をご覧ください。