🚀

Next.js 14まとめ

2023/10/27に公開

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

TL;DR

  • Turbopack: App & Pagesルーター向けの5000のテストをパス
    • ローカルサーバーの起動が53%高速化
    • Fast Refreshによるコードの更新が94%高速化
  • サーバーアクションの安定版: 進歩的に強化されたミューテーション
    • キャッシュと再検証の統合
    • シンプルな関数呼び出し、またはフォームとネイティブに連動
  • 部分的プリレンダリングのプレビュー版: 高速な初期の静的レスポンス+ストリーミングの動的コンテンツ
  • Next.js Learnの新規追加: Appルーターや認証、データベースなどを教える無料のコース

アップデート詳細

Next.jsコンパイラ

Next.js 13以降、Next.jsではPagesとAppルーターの両方でローカル開発のパフォーマンスを向上させるように取り組んできました。

以前は、この取り組みをサポートするためにnext devやNext.jsの他の部分を書き換えていました。その後、より漸進的なアプローチに変更しました。つまり、最初に全てのNext.jsの機能をサポートすることにフォーカスし直したので、Rustベースのコンパイラはまもなく安定版になるでしょう。

next dev向けの5000の結合テストがRustのエンジンを基礎とするTurbopackで現在パスしています。これらのテストは7年分のバグ修正と再現を含んでいます。

大規模なNext.jsアプリケーションであるvercel.comでのテストで以下を確認しています。

  • ローカルサーバーの起動が最大53.3%高速化
  • Fast Refreshによるコードの更新が最大94.7%高速化

このベンチマークは大規模なアプリケーション (および大規模なモジュールグラフ) で期待されるパフォーマンス向上の実用的な結果です。next dev向けのテストの90%が現在パスしているため、next dev --turboを使用するとより高速で信頼性の高いパフォーマンスを一貫して確認できるはずです。

テストの100%がパスしたら、次のマイナーリリースでTurbopackを安定版に移行するでしょう。また、カスタム設定やエコシステムプラグイン向けのwebpackの使用も引き続きサポートしていきます。

テストのパス率はこちらで確認できます。

フォームとミューテーション

Next.js 9でフロントエンドのコードのそばにバックエンドのエンドポイントを素早く構築できる方法としてAPIルートが導入されました。

例えば、api/ディレクトリ配下に以下のようなファイルを作成しました。

pages/api/submit.ts
import type { NextApiRequest, NextApiResponse } from 'next';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const data = req.body;
  const id = await createItem(data);
  res.status(200).json({ id });
}

そして、クライアントサイドで、ReactとAPIルートをフェッチするためのonSubmitのようなイベントハンドラを使用することができました。

pages/index.tsx
import { FormEvent } from 'react';
 
export default function Page() {
  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
 
    const formData = new FormData(event.currentTarget);
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData,
    });
 
    // Handle response if necessary
    const data = await response.json();
    // ...
  }
 
  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

現在Next.js 14では、データのミューテーションの認可の開発者体験をシンプルにしたいと考えています。さらに、ユーザーのネットワーク接続が遅い場合や、パワーの低いデバイスからフォームを送信する場合のユーザー体験を向上させたいと考えています。

サーバーアクションの安定版

APIルートを手動で作成する必要がないとしたらどうでしょうか?その代わりに、サーバーで安全に実行され、Reactコンポーネントから直接呼び出される関数を定義できるでしょう。

Appルーターはフレームワークが新機能を採用するために安定しているReact canaryチャンネルで構築されています。v14現在、Next.jsは最新のReact canaryにアップグレードしており、サーバーアクションの安定版を含んでいます。

先ほどのPagesルーターの例は一つのファイルにすることができます。

app/page.tsx
export default function Page() {
  async function create(formData: FormData) {
    'use server';
    const id = await createItem(formData);
  }
 
  return (
    <form action={create}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

サーバーアクションは過去にサーバー中心のフレームワークを使ったことがある開発者にとっては親しみを感じさせるものでしょう。フォームやFormData Web APIのようなウェブ標準の上に構築されています。

フォームを介してサーバーアクションを使用することは段階的な改善に役立ちますが、必須ではありません。フォームを介さずに、関数として直接呼び出すこともできます。TypeScriptを使用すると、クライアントとサーバーの間で完全なE2Eの型安全性が確保されます。

データの更新やページの再レンダリング、リダイレクトを1回のネットワークのラウンドトリップで行うことができるため、上流のプロバイダーが遅い場合でも、正しいデータがクライアンで表示されることを保証します。さらに、同じルート内の多くの異なるアクションを含む、異なるアクションを構成して再利用できます。

キャッシュや再検証、リダイレクトなど

サーバーアクションはAppルーターのモデル全体に深く統合されており、以下のようなことができます。

  • revalidatePath()revalidateTag()によるキャッシュされたデータの再検証
  • redirect()による異なるルートへのリダイレクト
  • cookies()によるクッキーのセットと読み取り
  • useOptimistic()による楽観的UI更新のハンドリング
  • useFormState()によるサーバーからのエラーの捕捉と表示
  • useFormStatus()によるクライアントでの読み込み中の状態の表示

サーバーアクションによるフォームとミューテーション、またはサーバーコンポーネントとサーバーアクション向けのセキュリティモデルとベストプラクティスについてはこちらを参照してください。

部分的プリレンダリングのプレビュー版

Next.jsのために取り組んでいる部分的なプリレンダリング (高速な初期の静的レスポンスと動的コンテンツのためのコンパイラ最適化) のプレビューを共有したいと思います。

部分的プリレンダリングはサーバーサイドレンダリング (SSR)、静的サイト生成 (SSG)、定期的な静的再検証 (ISR) に関する10年にわたる研究と開発の上に構築されています。

動機

皆さんのフィードバックをお聞きしました。現在ランタイム、設定オプション、レンダリング方法といったあまりに多くの考慮しなければならない事項があります。静的なスピードと信頼性を求めている一方で、完全に動的でパーソナライズされたレスポンスのサポートも求めています。

グローバルに優れたパフォーマンスとパーソナライゼーションを実現するために複雑さを犠牲にしてはいけません。

私たちの課題は、開発者が学ぶべき新しいAPIを導入することなく既存のモデルをシンプルにすることで、より良い開発者体験を生み出すことでした。サーバーサイドのコンテンツの部分的なキャッシュは存在しましたが、これらのアプローチは依然として私たちが目指す開発者体験とコンポーザビリティの目標を満たす必要があります。

部分的プリレンダリングは学ぶべき新しいAPIを必要としません

Reactサスペンスで構築する

部分的プリレンダリングはサスペンスの境界によって定義されます。その仕組みを説明します。以下のようなEコマースページを考えてみましょう。

app/page.tsx
export default function Page() {
  return (
    <main>
      <header>
        <h1>My Store</h1>
        <Suspense fallback={<CartSkeleton />}>
          <ShoppingCart />
        </Suspense>
      </header>
      <Banner />
      <Suspense fallback={<ProductListSkeleton />}>
        <Recommendations />
      </Suspense>
      <NewProducts />
    </main>
  );
}

部分的プリレンダリングが有効な場合、このページは<Suspense />の境界に基づいて静的な殻を生成します。Reactサスペンスからのfallbackはプリレンダリングされます。

殻の中のサスペンスのフォールバックは、カートを決定するためのクッキーを読み取ったり、ユーザーに基づいたバナーを表示したりするような動的コンポーネントに置き換えられます。

リクエストが行われると、静的なHTMLの殻はすぐに返却されます。

<main>
  <header>
    <h1>My Store</h1>
    <div class="cart-skeleton">
      <!-- Hole -->
    </div>
  </header>
  <div class="banner" />
  <div class="product-list-skeleton">
    <!-- Hole -->
  </div>
  <section class="new-products" />
</main>

<ShoppingCart />はユーザーのセッションを見るためにクッキーから読み取るので、このコンポーネントは静的な殻と同じHTTPリクエストの一部としてストリームされます。余分なネットワークラウンドトリップは必要ありません。

app/cart.tsx
import { cookies } from 'next/headers'
 
export default function ShoppingCart() {
  const cookieStore = cookies()
  const session = cookieStore.get('session')
  return ...
}

最もきめ細かい静的な殻を作るには、追加のサスペンスの境界を追加する必要があるかもしれません。しかし、今日loading.jsをすでに使用しているなら、これは暗黙のサスペンスの境界なので、静的な殻を生成するために変更は必要ありません。

近日公開

部分的プリレンダリングは活発に開発中です。次回のマイナーリリースでさらなるアップデートをお伝えする予定です。

メタデータの改善

ページのコンテンツがサーバーからストリームされる前に、最初にブラウザに送信される必要があるビューポートやカラースキーマ、テーマに関する重要なメタデータがあります。

これらのmetaタグが最初のページコンテンツと一緒に送信されるようにすることを保証することで、スムーズなユーザー体験が得られ、テーマカラーの変更によってページがちらついたり、ビューポートの変更によってレイアウトシフトが発生したりするのを防ぐことができます。

Next.js 14では、ブロッキングするメタデータとブロッキングしないメタデータを分離しました。ブロッキングするメタデータオプションはごく一部であり、ブロッキングしないメタデータが部分的にプリレンダリングされたページが静的な殻を返却するのを妨げないことを保証したいのです。

以下のメタデータオプションは現在非推奨であり将来のメジャーバージョンでmetadataから削除される予定です。

  • viewport: ビューポートの最初のズームと他のプロパティをセットする
  • colorScheme: ビューポートのためのサポートモード (ライト/ダーク) をセットする
  • themeColor: ビューポートの周囲のクロムの色をセットする

Next.js 14からは、これらのオプションに代わる新しいオプション、viewportgenerateViewportが追加されました。他の全てのmetadataオプションは変わりません。

今日からこれらの新しいAPIを採用し始めることができます。既存のmetadataオプションは引き続き動作します。

Next.js Learnコース

今日全く新しい無料のコースであるNext.js Learnをリリースしました。

Next.js Learnはフレームワークの基礎について何百万人もの開発者に教えてきており、新しく追加したものに対する皆さんのフィードバックを聞くのが待ちきれません。このコースを受講したい方はこちらにアクセスしてください。

その他のいくつかの改善

  • [破壊的変更] 最小のNode.jsバージョンが現在18.17
  • [破壊的変更] @next/fontのサポートを廃止し、next/fontをサポート
  • [破壊的変更] ImageResponseのimportをnext/serverからnext/ogに変更
  • [破壊的変更] next exportコマンドが非推奨になり、output: 'export'をサポート
  • など

Discussion