BLOG

ブログ

【Nuxt3】ハイブリッドレンダリングでSSRとSSGはどこまで共存できるのか

こんにちは、遠藤です!
こちらは、Mavs Advent Calendar2023の8日目の記事です!

今回は、Nuxt3のハイブリッドレンダリングでSSRとSSGがどこまで共存できるか、について現状調べたことをまとめたいと思います!

はじめに

本記事ではNuxt3の新機能ハイブリッドレンダリングを使用して、「一つのアプリケーション内でSSR(Server Side Rendering)とSSG(Static Site Generator)を共存させられるのか」について現状私が調べたことを紹介します!

なお、本記事は2023年11月現在のNuxt3の仕様であること、私がまだ知らないハイブリッドレンダリングの方法あるかもしれないということをご了承の上、一つの参考としてご覧いただけますと幸いです!

また、Nuxt3からSSRがユニバーサルレンダリングという表現に変更になっていますが、本記事内ではSSRと表現させていただきます。

ユニバーサルレンダリングとは

ユニバーサルレンダリングはNuxt3のデフォルトのレンダリングモードです。
サーバーサイドとクライアントサイド両方でレンダリングしてコンテンツを表示します。
ページ遷移やインタラクティブな動作などのクライアントサイドの利点を失わずに、
サーバーサイドでもレンダリングを行うことができます。

結論

結論から言うと完全ではありませんが、Nuxt3ではハイブリッドレンダリングを使用して、ページごとにSSRかSSGかを設定することができます!

例えば、/test1(pages/test1.vue)はSSRでレンダリングし、/test2(pages/test2.vue)はSSGのような形でレンダリングする、ということが可能です。

「SSGのような形」と表現したのは、Nuxt3のハイブリッドレンダリングが基本的にはSSRで動くこと前提であるためです。完全なSSGとしてデプロイする場合は、nuxt generate ですべてSSGとしてデプロイする必要があるため、この場合はハイブリッドレンダリングの機能を使用することができません。

では、どのようにSSGのようなbuildをするのか、というとprerenderという設定を使用します。

prerenderについて

ファイルごとにprerenderを設定することで、デプロイの際に事前にHTMLファイルなどの静的ファイルを生成しておき、ユーザーがアクセスした際に事前にレンダリングされたページ情報を返すSSGのような挙動が可能です。

コードは下記の通りです。

export default defineNuxtConfig({
...中略

 // ルートごとに設定します
  routeRules: {
    "/": { ssr: true, prerender: true },
    "/": { ssr: true, prerender: true },
    "/[id]": { ssr: true, prerender: true },
    "/contact": { ssr: true, prerender: false },
  },
})

しかし、prerenderを設定したページ内で、APIアクセスによる情報を取得する関数などを設定している場合、ページの読み込みと同時にこの関数が動作してしまうため、思わぬ不具合が発生する場合があります。

なぜこのような動きになるかというと、通常nuxt generateの際はpayloadが作成されるため、JavaScriptの記述は基本的にはpayloadから取得されます。 APIにアクセスする関数もアクセスした後の結果としてpayload内に記述されるため、ページが呼び出されても関数が発火しないイメージです。

ですが、prerenderはあくまでSSRの機能であり、build時にpayloadを作成しないため、ページにアクセスすると関数が動作してしまいます。

例えば、microCMSからAPIでブログ情報を取得し表示するページを例に挙げます。 SSRの場合はページを表示するたびにAPIアクセス用の関数が動作し、情報を取得するためページ表示に少しラグがあります。一方でSSG(nuxt generate)の場合は、ページを表示する際に事前にレンダリングされた静的なファイル情報(HTMLなど)を取得し表示するので、ページ読み込みの際にもAPIが動作することはありません。

prerenderを設定したvueファイルの場合、この中間のような挙動をします。上記の例になぞると、事前にレンダリングしていたページを表示しつつ、API関数も動作する、といった具合です。

上記のmicroCMSの例の場合だと、本来のSSGに期待する「事前にレンダリングした静的なページを早く画面に表示する」という要件を満たせなくなります。(結局SSRと同じ挙動になってしまうため)

静的なvueファイルにはprerenderが有効ですが、動的なファイルをSSG時の挙動にするためにはprerenderを設定したファイルで動的な関数にならないようにpayloadを作成して、静的なファイルとしてbuildする必要がありそうです。

果たしてそんな方法があるのでしょうか…

payloadExtentionについて

調べている中で、payloadExtentionという設定を見つけました!

こちらはまだ開発段階の機能で正式実装ではないのですが、この設定を使用するとprerenderを指定したルーティングをpayload作成する形でデプロイすることができます!

これにより上記で解決できなかったページを読み込むたびに関数が発火してしまう問題を解決することができます!具体的には下記のような記述をnuxt.configに追記します。

  routeRules: {
    "/": { ssr: true, prerender: true },
    "/": { ssr: true, prerender: true },
    "/[id]": { ssr: true, prerender: true },
    "/contact": { ssr: true, prerender: false },
  },
  experimental: {
    payloadExtraction: true,
  },

注意点

魔法のようなpayloadExtention ですが、正式実装ではないため予期せぬ挙動が起きる場合があります。
業務等で使用する際は、正式な実装されてから取り扱うことをおすすめいたします。

さいごに

今回はNuxt3の目玉機能、ハイブリッドレンダリングに触れてみました!!

ページの表示速度はWebアプリケーションを使用する上でとても重要だと感じています。また、今回は紹介していませんが、Nuxt3には他にも SPA / ISR / ISG といったレンダリング方法があり、上記で紹介した例とともに活用することで、柔軟なレンダリング方法を採用することができるみたいです!
より詳しく知りたい方はNuxt3の公式を確認してみて下さい!!

見た目を整えるコードの記述だけではなく、レンダリングの方法やデータの取り扱い方に触れることができるのがフロントエンドエンジニアの楽しさだなぁと、調べながら実感しました!

まだまだNuxt3は便利になりそうなので引き続き調べていきたいと思います〜!!
ではまた!

RELATED ARTICLE