Next.js14の実験的機能 Partial Prerendering を学ぶ

# はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。（同担OKです😉）
今更ながら、Next.jsのバージョン14で実験的に追加された**Partial Prerendering**について触れてみようと思います！


# Partial Prerenderingとは
https://nextjs.org/learn/dashboard-app/partial-prerendering

> Next.js 14 contains a preview of Partial Prerendering – an experimental feature that allows you to render a route with a static loading shell, while keeping some parts dynamic. In other words, you can isolate the dynamic parts of a route.

レンダリングの最適化を図る機能で、動的なコンテンツが含まれているページにおいて、動的なコンテンツを非同期で読み込むようにしつつ、静的なコンテンツは事前にビルドされたものをレンダリングする事ができるようです！革新的だあ。。。😮

![スクリーンショット 2024-06-16 19.08.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653241/ec70bb8e-fc7c-848d-4648-fc5f16e306cf.png)

上記画像の例で説明しますと、ユーザがページを訪れた際
1. 静的なコンテンツ（NavbarやProduct Information）はビルド時に生成された`index.html`を表示する
1. 動的なコンテンツ（CartやRecommended）はReact18のSuspenceコンポーネントを用いて非同期かつ並列でレンダリングされる

このような処理が行われることで、レンダリングの高速化が行われているようです！

# セットアップ
Next.jsのプロジェクトで実験的に使える機能なので、まずは最新のCanaryバージョンに変更しましょう
``` zsh
$ npm uninstall next
$ npm install next@canary
$ npm install next@canary
```
依存関係でエラーが発生する場合は、以下のオプションを付与してください。
``` zsh
$ npm install next@canary --legacy-peer-deps
```

次に、最新のCanaryバージョンではReact 19.0.0以上を必要とするため、バージョンを変更します。
``` zsh
$ npm uninstall react react-dom
$ npm install react@beta react-dom@beta
```

最後に、`next.config.js`で`ppr`機能を有効にします。
``` next.config.js
/* @type {import('next').NextConfig} */
const nextConfig = {
   experimental: {
     ppr: true,
   },
};

export default nextConfig;
```

# Partial Prerenderingを使ってみる
適当に動的コンテンツを含んだページを作成してみましょう。
``` page.tsx
import { Suspense } from "react";
import { Articles } from "./components/Articles";

export default function Page() {
  return (
    <main>
      <h1>Articles</h1>
      <h2>this is new articles!!</h2>
      <Suspense fallback={<h2>Loading...</h2>}>
        {/* 動的コンテンツ */}
        <Articles />
      </Suspense>
    </main>
  );
}
```

このプロジェクトをビルドしてみると。。。
``` zsh
Route (app)                              Size     First Load JS
┌ ◐ /                                    136 B          90.4 kB
└ ○ /_not-found                          896 B          91.2 kB
+ First Load JS shared by all            90.3 kB
  ├ chunks/440-cd21406ea91811eb.js       36.4 kB
  ├ chunks/f5e865f6-81b5b70afb154a38.js  52.1 kB
  └ other shared chunks (total)          1.87 kB


○  (Static)             prerendered as static content
◐  (Partial Prerender)  prerendered as static HTML with dynamic server-streamed content
```

おお！きちんと`Partial Prerender`という結果になっていますね！
ちなみに、元の状態ですと`Dynamic`になっています。
``` zsh
Route (app)                              Size     First Load JS
┌ ƒ /                                    136 B          87.2 kB
└ ○ /_not-found                          875 B          87.9 kB
+ First Load JS shared by all            87 kB
  ├ chunks/23-ef3c75ca91144cad.js        31.5 kB
  ├ chunks/fd9d1056-2821b0f0cabcd8bd.js  53.7 kB
  └ other shared chunks (total)          1.85 kB


○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand
```
`Partial Prerendering`で表示速度が改善されるようなので、ベンチマークを測定してみましょう！
指標としては、サーバにリクエストされてからDOMツリーが構築されるまでの時間である`DOMContentLoaded`を使います！（簡単に測れるので🤫）

結果は、

pprあり
DOMContentLoaded: 164ms

pprなし
DOMContentLoaded: 227ms

最小限のページでも、少しは改善されるようです！これはすごい！
早い内にStable版としてリリースされて欲しいですね！😎

# おわりに
今回は、簡単に`Partial Prerender`を触ってみました！
どんどん表示速度が速くなるのは凄いですが、それに頼らず出来る限りチューニングしないとなあ。。。と感じさせられましたね🥶

もしかすると間違った情報を掲載している可能性もあるため、気付いた方がいらっしゃればコメントにてご指摘いただけると幸いです！

以上、センリツでした🤓