🚀

Next.js 15 RCまとめ

2024/05/26に公開

基本的には以下のNext.js 15 RCのブログを翻訳してまとめたものになります。
https://nextjs.org/blog/next-15-rc

TL;DR

Next.js 15 RCを試すにはNext.jsとReactのRC版が必要です。

npm install next@rc react@rc react-dom@rc

アップデート詳細

React 19 RC

Next.jsのApp RouterはフレームワークのためのReactのカナリアチャンネルの上で構築されているため、開発者はReact 19がリリースされるまえにこれらの新しいAPIを使用し、フィードバックを提供できます。

Next.js 15 RCはReact 19 RCをサポートし、それはクライアントとActionsのようなサーバーの両方の新機能を含んでいます。

詳細は以下をご覧ください。

React Compiler (Experimental)

React CompilerはMetaのReactチームによって作成された新しい実験的なコンパイラです。コンパイラはプレーンなJavaScriptのセマンティクスとReactのルールを理解することで深いレベルでコードを理解し、コードに自動的な最適化を加えることができます。コンパイラは開発者がuseMemouseCallbackのようなAPIで行わなければならない手動のメモ化の量を減らし、コードをよりシンプルに、保守しやすく、エラーを少なくしてくれます。

Next.js 15 RCでReact Compilerを試すにはbabel-plugin-react-compilerをインストールしてください。

npm install babel-plugin-react-compiler

次に、next.config.jsexperimental.reactCompilerのオプションを追加してください。

next.config.js
const nextConfig = {
  experimental: {
    reactCompiler: true,
  },
};

module.exports = nextConfig;

オプションとして、以下のように「オプトイン」モードで実行するようにコンパイラを設定できます。

next.config.js
const nextConfig = {
  experimental: {
    reactCompiler: {
      compilationMode: 'annotation',
    },
  },
};

module.exports = nextConfig;

詳細は以下をご覧ください。

Next.jsでの検証としては以下の記事が参考になります。
https://zenn.dev/cybozu_frontend/articles/next-react-compiler

また、Reactでの検証としては以下の記事が参考になります。
https://zenn.dev/kazukix/articles/react-compiler

ハイドレーションエラーの改善

ハイドレーションエラーはエラーの対応方法の提案とともにエラーが発生した箇所のコードを表示するようになりました。

ビフォーアフターの画像について、ブログに貼られているのでそちらをご覧ください。

キャッシュに関するアップデート

Next.js 15では、fetchによるリクエストとGETによるRoute Handlers、Client Routerのキャッシュのデフォルトを、キャッシュありからキャッシュなしに変更しました。以前の振る舞いを維持したい場合は、引き続きキャッシュをオプトインできます。

Next.jsのキャッシュは今後数ヶ月に渡って改善され続けます。更なる詳細はNext.js 15 GAの発表でお伝えします。

fetchによるリクエストのキャッシュのデフォルト無効化

Next.jsはサーバーサイドのfetchによるリクエストがフレームワークの永続的なHTTPキャッシュとどのように相互作用するかを設定するためにWeb fetch APIを拡張したcacheオプションを使用しています。

fetch('https://...', { cache: 'no-store' | 'force-cache' });
  • no-store: 全てのリクエストでリモートサーバーからリソースを取得し、キャッシュを更新しない
  • force-cache: キャッシュ(存在すれば)、またはリモートサーバーからリソースを取得し、キャッシュを更新する

Next.js 14では、cacheオプションが設定されていない場合、Dynamic Functuins、またはDynamic Config Optionが使用されていない限り、force-cacheがデフォルトで使用されていました。

Next.js 15では、cacheオプションが設定されていない場合はno-storeがデフォルトで使用されます。これはfetchによるリクエストがデフォルトでキャッシュされなくなることを意味します。

fetchによるリクエストのキャッシュをオプトインするには以下のようにしてください。

GETによるRoute Handlersのキャッシュのデフォルト無効化

Next.js 14では、GET HTTPメソッドを使用したRoute Handlersは、Dynamic Functuins、またはDynamic Config Optionが使用されていない限り、デフォルトでキャッシュされていました。

Next.js 15では、GET HTTPメソッドを使用したRoute Handlersはデフォルトでキャッシュされません。

export dynamic = 'force-static'のようなStatic Route Configを使用することでキャッシュをオプトインできます。

sitemap.tsopengraph-image.tsxicon.tsx、その他のMetadata Filesのような特別なRoute Handlersは、Dynamic Functuins、またはDynamic Config Optionが使用されていない限り、デフォルトで静的なままです。

PageコンポーネントのClient Router Cacheのデフォルト無効化

Next.js 14.2.0では、Router Cacheのカスタム設定ができる実験的なstaleTimesフラグが導入されました。

Next.js 15では、このフラグのデフォルトの振る舞いを変更し、Page segmentsに対するstaleTime0にします。これはアプリケーションを回遊する際、クライアントはナビゲーションの一部としてアクティブになるPageコンポーネントの最新のデータを常に反映することを意味します。しかし、依然として変わらない重要な振る舞いが存在します。

  • 共通のLayoutのデータはPartial Renderingをサポートし続けるためにサーバーから再取得されない
  • 戻る/進むナビゲーションはブラウザがスクロール位置を復元できるようにキャッシュから復元される
  • loading.jsは5分間(、またはstaleTimes.staticの設定値)キャッシュされる

以下のように設定することで以前のClient Router Cacheの振る舞いをオプトインできます。

next.config.js
const nextConfig = {
  experimental: {
    staleTimes: {
      dynamic: 30,
    },
  },
};

module.exports = nextConfig;

キャッシュに関するアップデートについては以下の記事が参考になります。
https://zenn.dev/akfm/articles/nextjs-cache-default-update

段階的なPartial Prerendering (Experimental) の採用

Next.js 14では、同じページで静的レンダリングと動的レンダリングを組み合わせる最適化として、Partial Prerendering (PPR) が導入されました。

Next.jsは現在、cookies()headers()、キャッシュされないデータリクエストのようなDynamic Functionsが使用されていない限り、デフォルトで静的レンダリングになります。これらのAPIはRoute全体を動的レンダリングにオプトインします。PPRを使用すれば、Suspense境界であらゆる動的UIをラップできます。新しいリクエストが来ると、Next.jsはすぐに静的HTMLの殻を返し、次に同じHTTPリクエストの中で動的部分をレンダーしてストリームします。

段階的な採用のために、特定のLayoutsとPagesをPPRにオプトインするexperimental_ppr Route設定オプションが追加されました。

app/page.tsx
import { Suspense } from "react";
import { StaticComponent, DynamicComponent } from "@/app/ui";

export const experimental_ppr = true;

export default function Page() {
  return (
     <>
	     <StaticComponent />
	     <Suspense fallback={...}>
		     <DynamicComponent />
	     </Suspense>
     </>
  );
}

新しいオプションを使用するために、next.config.jsexperimental.ppr設定を'incremental'にする必要があります。

next.config.js
const nextConfig = {
  experimental: {
    ppr: 'incremental',
  },
};

module.exports = nextConfig;

全てのSegmentsでPPRが有効になったら、ppr値をtrueに設定し、アプリケーション全体と全ての将来のRoutesで有効にするのが安全だと考えられます。

PPRのロードマップについての更なる詳細はNext.js 15 GAの発表でお伝えします。

詳細は以下をご覧ください。

レスポンスの後にコードを実行できるnext/after (Experimental)

ユーザーのリクエストを処理する際、サーバーは通常レスポンスの計算に直接関係するタスクを実行します。しかし、ログや分析、その他の外部システムとの同期などのタスクを実行する必要があるかもしれません。

これらのタスクはレスポンスと直接関係ないので、ユーザーはそれらが完了するまで待たされるべきではありません。Serverless Functionsはレスポンスが終了するとすぐに計算を停止するため、ユーザーへのレスポンス後のタスクを延期することは課題となります。

after()はこの問題を解決する新しい実験的なAPIで、レスポンスがストリーミングを終了した後に処理するタスクをスケジューリングできるようにし、プライマリ・レスポンスをブロックすることなくセカンダリ・タスクを実行できるようにします。

使用するには、next.config.jsexperimental.afterを追加してください。

next.config.js
const nextConfig = {
  experimental: {
    after: true,
  },
};

module.exports = nextConfig;

次に、Server ComponentsやServer Actions、Route Handlers、Middlewareで関数をインポートしてください。

import { unstable_after as after } from 'next/server';
import { log } from '@/app/utils';

export default function Layout({ children }) {
  // セカンダリ・タスク
  after(() => {
    log();
  });

  // プライマリ・レスポンス
  return <>{children}</>;
}

詳細は以下をご覧ください。

create-next-appのアップデート

  • 新しいデザイン
  • ローカル開発でTurbopackを有効化するかどうかを尋ねる新しいプロンプト(デフォルトはNo)と--turboフラグ
    • npx create-next-app@rc --turbo
      
  • 新しいプロジェクトをより簡単に始めるための--emptyフラグ。これで余計なファイルやスタイルが削除された最小限の「hello world」ページになる
    • npx create-next-app@rc --empty
      

外部パッケージのバンドルの最適化 (Stable)

外部パッケージをバンドルするとアプリケーションのコールドスタートのパフォーマンスが向上します。

App Routerでは、外部パッケージはデフォルトでバンドルされ、新しいserverExternalPackages設定オプションを使用することで特定のパッケージをオプトアウトできます。

Pages Routerでは、外部パッケージはデフォルトでバンドルされませんが、既存のtranspilePackages設定オプションを使用することでバンドルするパッケージの一覧を指定できます。この設定オプションでは、各パッケージを指定する必要があります。

App&Pages Router間の設定を統一するために、App Routerのデフォルトの自動バンドルに適したbundlePagesRouterDependenciesという新しいオプションを導入します。必要に応じて、serverExternalPackagesを使用することで特定のパッケージをオプトアウトできます。

next.config.js
const nextConfig = {
  // 自動的にPages Routerで外部パッケージをバンドルする
  bundlePagesRouterDependencies: true,
  // App&Pages Routerの両方で特定のパッケージをバンドルからオプトアウトする
  serverExternalPackages: ['package-name'],
};

module.exports = nextConfig;

詳細は以下をご覧ください。

その他のいくつかの改善

  • [Breaking] Reactの最低バージョンが19 RCに
  • [Breaking] next/font: 外部の@next/fontパッケージのサポートを削除
  • など

Discussion