Nuxt Nation カンファレンスが開催されます。11月12日~13日にご参加ください。

レンダリングモード

Nuxtで利用可能なさまざまなレンダリングモードについて学びましょう。

Nuxtは、さまざまなレンダリングモードをサポートしています。 ユニバーサルレンダリングクライアントサイドレンダリングだけでなく、 ハイブリッドレンダリング、および CDNエッジサーバーでのアプリケーションのレンダリングも可能です。

ブラウザとサーバーの両方がJavaScriptコードを解釈して、Vue.jsコンポーネントをHTML要素に変換できます。このステップを**レンダリング**と呼びます。 Nuxtは、**ユニバーサル**レンダリングと**クライアントサイド**レンダリングの両方をサポートしています。この2つのアプローチには、これから説明するメリットとデメリットがあります。

デフォルトでは、Nuxtは、より良いユーザーエクスペリエンス、パフォーマンス、および検索エンジンのインデックス作成を最適化するために**ユニバーサルレンダリング**を使用しますが、 設定の1行でレンダリングモードを切り替えることができます。

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

このステップは、PHPまたはRubyアプリケーションによって実行される従来の**サーバーサイドレンダリング**に似ています。ブラウザがユニバーサルレンダリングを有効にしてURLを要求すると、Nuxtはサーバー環境でJavaScript(Vue.js)コードを実行し、完全にレンダリングされたHTMLページをブラウザに返します。 Nuxtは、ページが事前に生成された場合、キャッシュから完全にレンダリングされたHTMLページを返すこともできます。ユーザーは、クライアントサイドレンダリングとは異なり、アプリケーションの初期コンテンツ全体をすぐに取得できます。

HTMLドキュメントがダウンロードされると、ブラウザはこれを解釈し、Vue.jsがドキュメントの制御を引き継ぎます。以前にサーバーで実行された同じJavaScriptコードが、クライアント(ブラウザ)で**再度**バックグラウンドで実行され、HTMLにリスナーをバインドすることにより、インタラクティビティを有効にします(したがって**ユニバーサルレンダリング**)。これは**ハイドレーション**と呼ばれます。ハイドレーションが完了すると、ページは動的なインターフェースやページ遷移などのメリットを享受できます。

ユニバーサルレンダリングにより、Nuxtアプリケーションは、クライアントサイドレンダリングのメリットを維持しながら、迅速なページ読み込み時間を提供できます。さらに、コンテンツはすでにHTMLドキュメントに存在するため、クローラーはオーバーヘッドなしでインデックスを作成できます。

Users can access the static content when the HTML document is loaded. Hydration then allows page's interactivity

サーバーレンダリングとクライアントレンダリング

ユニバーサルレンダリングモードで、Vueファイルのどの部分がサーバーおよび/またはクライアントで実行されるか質問するのは当然です。

app.vue
<script setup lang="ts">
const counter = ref(0); // executes in server and client environments

const handleClick = () => {
  counter.value++; // executes only in a client environment
};
</script>

<template>
  <div>
    <p>Count: {{ counter }}</p>
    <button @click="handleClick">Increment</button>
  </div>
</template>

最初の要求では、counter refが<p>タグ内でレンダリングされるため、サーバーで初期化されます。 handleClickの内容はここでは実行されません。ブラウザでのハイドレーション中に、counter refが再初期化されます。 handleClickは最後にボタンにバインドされます。したがって、handleClickの本体は常にブラウザ環境で実行されると推測するのが妥当です。

ミドルウェアページは、サーバーとハイドレーション中のクライアントで実行されます。 プラグインは、サーバーまたはクライアント、またはその両方でレンダリングできます。 コンポーネントは、クライアントでのみ実行されるように強制することもできます。 コンポーザブルユーティリティは、その使用状況に応じてレンダリングされます。

サーバーサイドレンダリングの利点

  • パフォーマンス:ブラウザはJavaScriptで生成されたコンテンツよりも静的コンテンツをはるかに高速に表示できるため、ユーザーはページコンテンツにすぐにアクセスできます。同時に、Nuxtはハイドレーションプロセス中にWebアプリケーションのインタラクティビティを保持します。
  • 検索エンジン最適化:ユニバーサルレンダリングは、従来のサーバーアプリケーションとして、ページ全体のHTMLコンテンツをブラウザに配信します。 Webクローラーはページのコンテンツを直接インデックス化できるため、ユニバーサルレンダリングは、すばやくインデックス化したいコンテンツに最適です。

サーバーサイドレンダリングの欠点

  • 開発上の制約:サーバー環境とブラウザ環境は同じAPIを提供していないため、両側でシームレスに実行できるコードを記述するのは難しい場合があります。幸いなことに、Nuxtは、コードの実行場所を判断するのに役立つガイドラインと特定の変数を提供しています。
  • コスト:ページをその場でレンダリングするには、サーバーを実行する必要があります。これにより、従来のサーバーと同様に月額費用が発生します。ただし、クライアントサイドナビゲーションを引き継ぐブラウザによるユニバーサルレンダリングのおかげで、サーバー呼び出しは大幅に削減されます。 エッジサイドレンダリングを活用することで、コスト削減が可能です。

ユニバーサルレンダリングは非常に用途が広く、ほぼすべてのユースケースに適合し、特にコンテンツ指向のWebサイト、**ブログ、マーケティングWebサイト、ポートフォリオ、eコマースサイト、およびマーケットプレイス**に最適です。

ハイドレーションの不一致なしにVueコードを記述する方法の詳細については、Vueドキュメントを参照してください。
ブラウザAPIに依存し、副作用があるライブラリをインポートする場合は、インポートするコンポーネントがクライアント側でのみ呼び出されるようにしてください。バンドラーは、副作用を含むモジュールのインポートをツリーシェイクしません。

クライアントサイドレンダリング

すぐに使える従来のVue.jsアプリケーションは、ブラウザ(または**クライアント**)でレンダリングされます。次に、Vue.jsは、ブラウザが現在のインターフェイスを作成する手順を含むすべてのJavaScriptコードをダウンロードして解析した後、HTML要素を生成します。

Users have to wait for the browser to download, parse and execute the JavaScript before seeing the page's content

クライアントサイドレンダリングの利点

  • 開発速度:クライアント側のみで作業する場合、たとえば、windowオブジェクトなどのブラウザ専用のAPIを使用することで、コードのサーバー互換性を心配する必要はありません。
  • 安価:サーバーを実行すると、JavaScriptをサポートするプラットフォームで実行する必要があるため、インフラストラクチャのコストが増加します。クライアントのみのアプリケーションは、HTML、CSS、およびJavaScriptファイルを使用して、任意の静的サーバーでホストできます。
  • オフライン:コードはすべてブラウザで実行されるため、インターネットが利用できない場合でも正常に動作し続けることができます。

クライアントサイドレンダリングの欠点

  • パフォーマンス:ユーザーは、ブラウザがJavaScriptファイルをダウンロード、解析、実行するのを待つ必要があります。ダウンロード部分のネットワークと、解析と実行を行うユーザーのデバイスによっては、時間がかかり、ユーザーエクスペリエンスに影響を与える可能性があります。
  • 検索エンジン最適化:クライアントサイドレンダリングを介して配信されるコンテンツのインデックス作成と更新には、サーバーレンダリングされたHTMLドキュメントよりも時間がかかります。これは、検索エンジンのクローラーが、ページにインデックスを付けるために最初に完全にレンダリングされるのを待たないため、先に説明したパフォーマンスの欠点に関連しています。コンテンツが、純粋なクライアントサイドレンダリングで検索結果ページに表示および更新されるのに時間がかかります。

クライアントサイドレンダリングは、インデックス作成を必要としない、またはユーザーが頻繁に訪問する、インタラクティブ性の高い**Webアプリケーション**に最適です。**SaaS、バックオフィスアプリケーション、またはオンラインゲーム**など、後続の訪問時にダウンロードフェーズをスキップするためにブラウザキャッシュを活用できます。

nuxt.config.tsでNuxtを使用したクライアントサイドのみのレンダリングを有効にできます。

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false
})
もし ssr: false を使用する場合、アプリがハイドレートされるまで表示されるローディング画面をレンダリングするために使用するHTMLファイルを ~/app/spa-loading-template.html に配置する必要があります。
詳しくは、SPAローディングテンプレートをご覧ください。
Alexander Lichter氏によるNuxtでプレーンなSPAを構築する!?に関するビデオをご覧ください。

静的なクライアントレンダリングアプリのデプロイ

nuxi generate または nuxi build --prerender コマンドを使用して、アプリを静的ホスティングにデプロイする場合、Nuxtはデフォルトで各ページを個別の静的HTMLファイルとしてレンダリングします。

完全にクライアントサイドレンダリングを使用している場合、これは不要かもしれません。必要なのは、単一の index.html ファイルと、すべてのリクエストに対して静的Webホストに提供させる 200.html および 404.html のフォールバックのみかもしれません。

これを実現するために、ルートのプリレンダリング方法を変更できます。nuxt.config.tsフックにこれを追加するだけです。

nuxt.config.ts
export default 
defineNuxtConfig
({
hooks
: {
'prerender:routes' ({
routes
}) {
routes
.
clear
() // Do not generate any routes (except the defaults)
} }, })

これにより、3つのファイルが生成されます。

  • index.html
  • 200.html
  • 404.html

200.html および 404.html は、使用しているホスティングプロバイダーに役立つ場合があります。

ハイブリッドレンダリング

ハイブリッドレンダリングでは、ルートルールを使用してルートごとに異なるキャッシングルールを適用し、指定されたURLへの新しいリクエストに対してサーバーがどのように応答するかを決定します。

以前は、Nuxtアプリケーションとサーバーのすべてのルート/ページで、ユニバーサルまたはクライアントサイドの同じレンダリングモードを使用する必要がありました。さまざまなケースで、一部のページはビルド時に生成でき、他のページはクライアントサイドでレンダリングする必要があります。たとえば、管理者セクションがあるコンテンツWebサイトを考えてみてください。すべてのコンテンツページは、主に静的であり、一度生成されるべきですが、管理者セクションは登録を必要とし、より動的なアプリケーションのように動作します。

Nuxtには、ルートルールとハイブリッドレンダリングのサポートが含まれています。ルートルールを使用すると、Nuxtルートのグループのルールを定義したり、レンダリングモードを変更したり、ルートに基づいてキャッシュ戦略を割り当てたりできます。

Nuxtサーバーは、対応するミドルウェアを自動的に登録し、Nitroキャッシングレイヤーを使用してルートをキャッシュハンドラーでラップします。

nuxt.config.ts
export default 
defineNuxtConfig
({
routeRules
: {
// Homepage pre-rendered at build time '/': {
prerender
: true },
// Products page generated on demand, revalidates in background, cached until API response changes '/products': {
swr
: true },
// Product pages generated on demand, revalidates in background, cached for 1 hour (3600 seconds) '/products/**': {
swr
: 3600 },
// Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds) '/blog': {
isr
: 3600 },
// Blog post page generated on demand once until next deployment, cached on CDN '/blog/**': {
isr
: true },
// Admin dashboard renders only on client-side '/admin/**': {
ssr
: false },
// Add cors headers on API routes '/api/**': {
cors
: true },
// Redirects legacy urls '/old-page': {
redirect
: '/new-page' }
} })

ルートルール

使用できるさまざまなプロパティは次のとおりです。

  • redirect: string - サーバーサイドのリダイレクトを定義します。
  • ssr: boolean - アプリのセクションのHTMLのサーバーサイドレンダリングを無効にし、ssr: false を使用してブラウザーでのみレンダリングするようにします。
  • cors: boolean - cors: true でcorsヘッダーを自動的に追加します - headers で上書きすることにより、出力をカスタマイズできます。
  • headers: object - 特定のヘッダーをサイトのセクション(たとえば、アセット)に追加します。
  • swr: number | boolean - サーバー応答にキャッシュヘッダーを追加し、構成可能なTTL(Time To Live)のためにサーバーまたはリバースプロキシにキャッシュします。Nitroの node-server プリセットは、完全な応答をキャッシュできます。TTLが期限切れになると、ページがバックグラウンドで再生成されている間、キャッシュされた応答が送信されます。trueが使用されると、MaxAgeなしで stale-while-revalidate ヘッダーが追加されます。
  • isr: number | boolean - 動作は swr と同じですが、これをサポートするプラットフォーム(現在はNetlifyまたはVercel)で応答をCDNキャッシュに追加できます。true を使用した場合、コンテンツはCDN内の次のデプロイまで保持されます。
  • prerender: boolean - ビルド時にルートをプリレンダリングし、静的アセットとしてビルドに含めます。
  • experimentalNoScripts: boolean - サイトのセクションに対するNuxtスクリプトおよびJSリソースヒントのレンダリングを無効にします。
  • appMiddleware: string | string[] | Record<string, boolean> - アプリケーションのVueアプリ部分(つまり、Nitroルートではない)内のページパスに対して実行する必要があるミドルウェアを定義できます。

可能な場合は常に、最適なパフォーマンスのために、ルートルールはデプロイプラットフォームのネイティブルールに自動的に適用されます(現在、NetlifyとVercelがサポートされています)。

nuxt generate を使用している場合、ハイブリッドレンダリングは利用できないことに注意してください。

サンプル

Nuxt Vercel ISR

Vercelにデプロイされたハイブリッドレンダリングを使用したNuxtアプリケーションの例。

エッジサイドレンダリング

エッジサイドレンダリング(ESR)は、Nuxtで導入された強力な機能であり、コンテンツデリバリーネットワーク(CDN)のエッジサーバーを介してユーザーの近くでNuxtアプリケーションをレンダリングできます。ESRを活用することで、パフォーマンスの向上とレイテンシの削減を保証し、それによってユーザーエクスペリエンスを向上させることができます。

ESRでは、レンダリングプロセスがネットワークの「エッジ」、つまりCDNのエッジサーバーにプッシュされます。ESRは、実際のレンダリングモードというよりもデプロイターゲットであることに注意してください。

ページの要求が行われると、元のサーバーまで進む代わりに、最も近いエッジサーバーによって傍受されます。このサーバーは、ページのHTMLを生成し、ユーザーに返送します。このプロセスは、データが移動する必要がある物理的な距離を最小限に抑え、レイテンシを削減し、ページの読み込みを高速化します

エッジサイドレンダリングは、Nuxt 3を強化するサーバーエンジンであるNitroのおかげで可能です。Node.js、Deno、Cloudflare Workersなどのクロスプラットフォームサポートを提供します。

現在、ESRを活用できるプラットフォームは次のとおりです。

ルートルールを使用してエッジサイドレンダリングを使用する場合、ハイブリッドレンダリングを使用できることに注意してください。

上記で言及したプラットフォームの一部にデプロイされたオープンソースの例を調べることができます。

Nuxt Todos Edge

ユーザー認証、SSR、およびSQLiteを備えたTodosアプリケーション。

Atinotes

Cloudflare KVに基づいたユニバーサルレンダリングによる編集可能なWebサイト。