リアクション スナップを使用したプリレンダリング ルート

サーバーサイド レンダリングではなく、React サイトのパフォーマンスを高速化したい場合は、プリレンダリングをお試しください。

react-snap は、サイト上のページを静的 HTML ファイルにプリレンダリングするサードパーティ ライブラリです。これにより、アプリケーションの最初のペイント時間が短縮されます。

シミュレートされた 3G 接続とモバイル デバイスに事前レンダリングを読み込んだ場合と読み込まなかった場合の、同じアプリの比較を次に示します。

読み込みの比較(並べて表示)。プリレンダリングを使用するバージョンは、4.2 秒速く読み込まれます。

なぜこれが有用なのでしょうか。

大規模なシングルページ アプリケーションの主なパフォーマンスの問題は、サイトを構成する JavaScript バンドルのダウンロードが完了するまで、ユーザーが実際のコンテンツを表示できないことです。バンドルが大きいほど、ユーザーは長く待たされることになります。

これを解決するために、多くのデベロッパーは、ブラウザで起動するだけでなく、サーバー上でアプリケーションをレンダリングするアプローチを採用しています。ページまたはルートの遷移ごとに、HTML 全体がサーバーで生成され、ブラウザに送信されます。これにより、最初の描画時間が短縮されますが、最初のバイトまでの時間が遅くなります。

プリレンダリングは、サーバー レンダリングよりも複雑ではありませんが、アプリケーションの First Paint 時間を短縮する方法も提供します。ヘッドレス ブラウザ(ユーザー インターフェースのないブラウザ)を使用して、ビルド時にすべてのルートの静的 HTML ファイルを生成します。これらのファイルは、アプリに必要な JavaScript バンドルと共に配布できます。

react-snap

react-snap は、Puppeteer を使用して、アプリケーション内の異なるルートのプリレンダリングされた HTML ファイルを作成します。まず、開発の依存関係としてインストールします。

npm install --save-dev react-snap

次に、package.jsonpostbuild スクリプトを追加します。

"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 がインライン化されたスタイル付きページが表示されています。

導入前と導入後の比較。後の写真は、クリティカル CSS がインライン化されているため、コンテンツがレンダリングされ、スタイルが設定されていることを示しています。

まとめ

アプリケーションにサーバー側のレンダリング ルートを使用しない場合は、react-snap を使用して静的 HTML をユーザーに事前レンダリングします。

  1. これを開発環境の依存関係としてインストールし、デフォルト設定をそのまま使用します。
  2. 試験運用版の inlineCss オプションを使用して、サイトで機能する場合は重要な CSS をインライン化します。
  3. ルート内のコンポーネント レベルでコード分割を使用している場合は、読み込み状態をユーザーにプリレンダリングしないように注意してください。詳しくは、react-snap README をご覧ください。