🆚

Next.js vs React レンダリングスピード対決

に公開

背景

私は最近よく、Next.jsを使用します。しかし、React+Viteを使用する人もよく見かけます。そこで双方のメリット/デメリットを調査していると、SSR(Server Side Rendering)CSR(Client Side Rendering)に違いがあるとわかりました。これは初期レンダリングに影響します。

この影響を感覚的なものではなく、数値で理論的なものにしていきましょう。

環境

  • Next.js (App Router, TypeScript)
  • Vite (React/TypeScript)
  • Google Chrome

プロジェクトの作成については、以下の記事を参考にしてください。

https://zenn.dev/uu5/articles/eb2c0edf5a1157
https://zenn.dev/uu5/articles/266901265e1a3e

アプリケーションの実行まで完了して、次に進んでください。

今回使用するページをできるだけ同じ記述量にするために、それぞれ以下のように書き換えます。

Next.js

src/app/page.tsx
export default function Home() {
  return (
    <div>
      <h1>Hello Next.js!</h1>
    </div>
  );
}

React + Vite

src/App.tsx
export default function App() {
  return (
    <div>
      <h1>Hello React+Vite!</h1>
    </div>
  );
}

Lighthouseの使用方法

chromeのWebページの品質監査を自動化ツールLighthouseを使用してレンダリングスピードを測ります。

まず、先ほど実行したchromeF12を押してデベロッパーツールを起動して、上のバーからLighthouseを選択します。

各種項目については、以下のように選択してください。

  • モード:ナビゲーション(デフォルト)
  • デバイス:デスクトップ
  • カテゴリ:全て選択

選択したら「ページ読み込みを分析」を押してください。監査が開始されます。

以下のようにスコアが表示されたら、監査完了です。
左がNext.js、右がReact + Viteになります。

スコアを見ると、パフォーマンスSEOに少し差があります。
今回は、パフォーマンスの一部について見ていきます。

【検証】 レンダリングスピード測定

Lighthouseを少しスクロールすると以下の指標が表示されています。

FCP LCP TBT CLS SI
Next.js 0.2s 0.3s 0ms 0 0.2s
React 0.9s 1.5s 0ms 0 0.9s

このようにFCPLCPに大きな差が出ています。

【追加検証】 画像のレンダリングスピード

画像の表示にどれくらいの時間がかるか検証します。

今回は比較のため、10MBのpng画像を以下のサイトからダウンロードして使用します。
https://sample-img.lb-product.com/10mb/

ダウンロードしたら、それぞれのプロジェクトのpublicディレクトリに入れてください。

次に、以下のように書き換えて、画像を表示させます。

Next.js

src/app/page.tsx
export default function Home() {
  return (
    <div>
      <h1>Hello Next.js!</h1>
+     <img src="/10MB.png" alt="" />
    </div>
  );
}

React + Vite

src/App.tsx
export default function App() {
  return (
    <div>
      <h1>Hello React+Vite!</h1>
+     <img src="/10MB.png" alt="" />
    </div>
  );
}

先ほどと同様にLighthouseで監査を実行します。

LCPを見ると、どちらも9秒以上かかっているのがわかります。

しかし、Next.jsには<Image>コンポーネントが存在し、これは簡単にいうと、画像を最適化してくれます。
この<Image>Next.jsで使用します。

src/app/page.tsx
+ import Image from "next/image";

export default function Home() {
  return (
    <div>
      <h1>Hello Next.js!</h1>
-         <img src="/10MB.png" alt="" />
+         <Image src="/10MB.png" alt="" width={640} height={640} />
    </div>
  );
}

Lighthouseで監査を実行してみましょう。

LCPは1.2秒となり、<Image>を使用しなかったときに比べて、大幅に速くなっています。

【考察】 なぜ、Next.jsのFCPやLCPが速いのか?

Next.js(App Router)の場合、SSR(Server Side Rendering)を採用しているため、サーバー側ですでにHTMLが生成された状態でブラウザに届きます。そのため、HTMLを受け取った瞬間に表示できます。

一方、React + Viteは、CSR(Client Side Rendering)であるため、以下の順でレンダリングが行われます。

  1. 空のHTMLとJavaScriptファイルがブラウザに届く
  2. JavaScriptを実行する
  3. DOMを生成して、描画する

このため、FCPLCPがNext.js(App Router)に比べて遅くなります。

【まとめ】 結局どっちを使うべき?

今回の検証では、Next.js(App Router)が初期レンダリングにおいて、優位であることがわかりました。

これは、ユーザーがWebページを訪れた瞬間にコンテンツを表示させたい場合(例えば、LPやブログ)に向いています。

しかし、初期表示速度を重視せず、シンプルな構成で開発体験を優先するなら、React + Viteを選ぶべきです。

Discussion