はじめに
React エコシステムにおいて、SSR サポートが最も優れているのはおそらく Next.js ですが、SSR は Next.js のすべてではなく、その提供するプリレンダリングサポートの 1 つに過ぎません:
-
SSG(Static Site Generation/Static Generation):静的生成。コンパイル時に静的 HTML を生成
-
SSR(Server-Side Rendering):サーバーサイドレンダリング。ユーザーリクエスト到来時に動的に HTML を生成
CSR 開始前に様々な方法でページコンテンツを事前にレンダリングし、ファーストスクリーンのパフォーマンスを向上させると同時に SEO のニーズを満たすこと。これがまさに Next.js の最も核心的な特性です
不仅如此、Next.js は混用サポートも提供し、異なるレンダリングモードを結合して使用し、相互補完的に融合させることが可能です。例えば:
-
ISR(Incremental Static Regeneration):増分静的再生成。ランタイムで定期的に静的 HTML を再生成
-
SSG から SSR へのダウングレード:事前に生成された静的 HTML にヒットしない場合、即座に SSR を実行
-
静的キャッシュ付き SSR:SSR 完了後、結果をキャッシュ。次回静的キャッシュにヒットすれば直接返却(SSG と同等)
-
SSG と CSR の結合:コンパイル時に静的部分(ページ外枠)を生成。CSR で動的部分(ページコンテンツ)を埋め
-
SSR と CSR の連携:URL 直接アクセスはより高速な SSR。SPA 遷移は体験がより優れる CSR
これらの繊細な混合レンダリングサポートにより、各種レンダリングモードがその優位性を十分に発揮でき、Next.js も一層彩りを添えています
SSG + SSR
SSG は SSR のレンダリングプロセスをコンパイル時に前倒しすることに相当し、これにより这部分の耗时を最適化し、極めて優れたページロードパフォーマンスを達成します。しかし明らかな欠陥も存在します——静的コンテンツのレンダリングにのみ使用可能。これにより本来非常に優れた方案が活躍の場を見つけにくくなります。では、その適用シナリオを拡大する方法はあるでしょうか?
あります。鍵は「静的」をどのように理解するかです。静的、動的は実際にはコンテンツの変化頻度を記述するものです。ほぼ(永遠に)変化しない、または変化頻度が非常に低いコンテンツを、私たちは静的コンテンツと呼びます。したがってコンテンツの変化に対処する方法を考えれば、SSG の適用シナリオを頻繁に変化しない「静的コンテンツ」から頻繁に変化しない「動的コンテンツ」に拡大する可能性があります
極限情况下、「頻繁に変化しない」は「毎回変化するわけではない」と等価です。つまり、リアルタイム/パーソナライズなど毎瞬動的に変化するコンテンツを除き、残りのシナリオはすべて SSG を使用可能です。もちろん、前提はコンテンツが必要な頻度で更新され生效することを保証することです。コンテンツ更新は実際には再 SSG なので、更新タイミングが不足しているだけです……
もう一つのそれほど明白ではない制限は静的コンテンツの数量です。レンダリング作業はコンパイル時にすべて完了する必要があるため、静的データが 100 万件あれば、100 万部の HTML をコンパイル生成する必要があります。1 回のコンパイルに数日かかる可能性があります……コンパイルコスト(時間/マシン問わず)はコンテンツ数量に伴い不断增加します。これは SSG レンダリングモードに生来備わった問題です。無解のように見えます。除非、コンパイル時に全量ページを生成しないのであれば……
ユーザーリクエスト面向の SSR は恰好な更新タイミングを提供でき、同時にコンパイルの下流として、SSR は漏れを阻止する機会があります。そこで、SSG と SSR は一拍即合。SSG は小部分のホットページのみをコンパイル生成し、残りはランタイムに SSR で生成します。ユーザーリクエスト到来時、コンテンツの更新が必要かによって SSR で再生成するか前回の生成物を使用するかを決定します:
Instead, you may statically generate a small subset of pages and use fallback: true for the rest. When someone requests a page that's not generated yet, the user will see the page with a loading indicator. Shortly after, getStaticProps finishes and the page will be rendered with the requested data. From now on, everyone who requests the same page will get the statically pre-rendered page.
Inspired by stale-while-revalidate, background regeneration ensures traffic is served uninterruptedly, always from static storage, and the newly built page is pushed only after it's done generating.
このように、SSG は適用シナリオを拡大し(高頻度変化のコンテンツ、編みきれない海量コンテンツ)、SSR はパフォーマンス優位性を獲得します(静的キャッシュ):
This ensures that users always have a fast experience while preserving fast builds and the benefits of Static Generation.
P.S. SSG と SSR の結合に関する詳細情報は、When is fallback: true useful?、Incremental Static Regeneration を参照
SSG + CSR
SSR と比較して、SSG のコストはより低く、ローカルで静的 HTML をコンパイル生成し、Web サーバーまたは CDN にホストするだけでプリレンダリングによるロードパフォーマンス向上を享受できます。アプリケーションサーバーの高額なマシンコストもなく、SSR オンラインサービスの可用性や運用保守作業を心配する必要もありません
SSR を借助して SSG の適用シナリオを拡大するには、それに伴うコスト問題を考慮する必要があります。では、よりコストの低い方法はあるでしょうか?
あります。しかし体験面で若干の妥協が必要です。SSG が静的コンテンツのレンダリングを得意としている既然、ページコンテンツを动静分離し、ページ上の静的部分を SSG にコンパイル生成させ、残りの動的部分は引き続き CSR で埋めることができます:
First, immediately show the page without data. Parts of the page can be pre-rendered using Static Generation. You can show loading states for missing data.
Then, fetch the data on the client side and display it when ready.
SSG と CSR を結合すれば、ページロードの白屏時間を短縮すると同時に、SSR の追加コストも回避できます。しかし、美中不足なのはロード体験が純粋な SSG より劣ることです。畢竟(ユーザーがより関心を持つ可能性がある)動的コンテンツはクライアントサイドで二次レンダリングされて初めて呈現され、SSG のように一度に完全なコンテンツを呈現することはできません。したがって、この方式がもたらすのはより多くの体験向上です。ユーザー知覚上ページロードが速くなったと感じます。一種の漸進式レンダリングモードと言えます
P.S. SSG と CSR の結合に関する詳細情報は、Fetching data on the client side を参照
SSR + CSR
SSG、SSR、CSR の 3 つが二つずつ結合する中で、最も耐人尋味なのはおそらくこの第三の組み合わせ——SSR と CSR の結合です
hydrate は除き、SSR と CSR にはまだ結合点があるでしょうか?
もちろんあります。SSR はページロードプロセス中の白屏時間を効果的に短縮でき、同時にページコンテンツを一度に完全に呈現する爽快な体験を提供できます。これと比較して、CSR のレンダリングパフォーマンスはクライアント環境に依存、データリクエストの遅滞などの欠点が無限大に大きくなり、CSR の高光優位性を覆い隠すほどになります:
-
無刷新でコンテンツをロード
-
ユーザー行動に応じてプリロード可能
これらの優位性はファーストスクリーンロードプロセス中では確かに體現されません。したがってページロードパフォーマンスのみを見るなら、SSR が CSR に完勝し、二者の中から 1 つを選択すればよく、結合の必要はありません。しかし、視点をユーザー操作の全フローに提升到げると、CSR と SSR が非常に融和した方式で完璧に結合できることがわかります:
-
ファーストスクリーンロードは SSR で:ユーザーが URL を通じて直接アクセスするのがホームページでも二级、三级ページでも、SSR はページを最速で呈現できます
-
站内遷移は CSR で:その後の交互操作中のページ遷移は、CSR でシームレスに新コンテンツをロード。さらにユーザー行動を予測して目標ページのコンテンツを事前にロードすることも可能
つまり、ファーストスクリーンロード作業はより高速な SSR に任せ、交互プロセス中は CSR に大展身手させるのです:
When you request this page directly, getServerSideProps runs at the request time, and this page will be pre-rendered with the returned props.
When you request this page on client-side page transitions through next/link or next/router, Next.js sends an API request to the server, which runs getServerSideProps. It'll return JSON that contains the result of running getServerSideProps, and the JSON will be used to render the page. All this work will be handled automatically by Next.js, so you don't need to do anything extra as long as you have getServerSideProps defined.
Next.js はこの結合方式に内蔵サポートを提供するだけでなく、可視領域中の站内リンクを自動でプリロードすることも可能です:
prefetch - Prefetch the page in the background. Defaults to true. Any <Link /> that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing prefetch={false}.
P.S. SSR と CSR の結合に関する詳細情報は、Only runs on server-side を参照
コメントはまだありません