Backブログに戻る

Next.js 15 RC 2 リリース

Next.js 15の2番目のリリース候補(RC2)が利用可能になりました。このバージョンでは、今後の安定版リリース前に最新機能をテストできます。

5月に発表した最初のNext.js 15リリース候補に続き、皆様からのフィードバックを基に2番目のリリース候補を準備しました。以下が私たちの取り組み内容です:

今すぐNext.js 15リリース候補(RC2)をお試しください:

# 新しい自動アップグレードCLIを使用
npx @next/codemod@canary upgrade rc
 
# または手動でアップグレード
npm install next@rc react@rc react-dom@rc

注: このリリース候補には前回のRCからのすべての変更が含まれています。

コーモッドCLIによるスムーズなアップグレード

各メジャーNext.jsリリースには、破壊的変更のアップグレードを自動化するコーモッド(自動コード変換)が含まれています。

さらにスムーズなアップグレードを実現するため、強化されたコーモッドCLIをリリースしました:

npx @next/codemod@canary upgrade rc

このツールは、コードベースを最新の安定版またはプレリリースバージョンにアップグレードするのに役立ちます。CLIは依存関係を更新し、利用可能なコーモッドを表示し、適用をガイドします。コマンドラインで指定したdistタグ(@rc@canaryなど)がアップグレード先のバージョンを決定します。

Next.jsコーモッドについて詳しく学ぶ。

開発用Turbopack

ローカル開発用のTurbopackは、Next.js 15の一般リリースで安定版となり、オプトイン方式を維持します。次のコマンドで今すぐ試せます:

next dev --turbo

Turbopackベータ版とリリース候補段階でテスト、問題報告、修正確認に参加した何千もの開発者のおかげで、54のGitHubイシューを解決しました。vercel.comv0.devnextjs.orgでの内部テストも多くの改善点を特定するのに役立ちました。

過去3ヶ月間、私たちはコールドコンパイルパフォーマンスの最適化に注力しました。前回リリースと比較して:

  • メモリ使用量が25–35%削減
  • 数千のモジュールを持つ大規模ページでコンパイルが30–50%高速化

今後もこれらの領域を最適化していきます。

Turbopackチームは、永続的キャッシュ、メモリ使用量削減、next build用Turbopackに大きな進展があり、テストの96%が通過しています。

注: Turbopackのサポート機能と非サポート機能をすべて確認してください。

非同期リクエストAPI(破壊的変更)

従来のサーバーサイドレンダリングでは、サーバーはリクエストを待ってからコンテンツをレンダリングします。しかし、すべてのコンポーネントがリクエスト固有のデータに依存しているわけではないため、リクエストを待つ必要はありません。理想的には、サーバーはリクエストが到着する前に可能な限り準備を整えるべきです。これを可能にし、将来の最適化の基盤を整えるため、リクエストを待つタイミングを知る必要があります。

そのため、headerscookiesparamssearchParamsなど、リクエスト固有のデータに依存するAPIを非同期化しています。

import { cookies } from 'next/headers';
 
export async function AdminPanel() {
  const cookieStore = await cookies();
  const token = cookieStore.get('token');
 
  // ...
}

これは破壊的変更であり、以下のAPIに影響します:

  • cookies
  • headers
  • draftMode
  • layout.jspage.jsroute.jsdefault.jsgenerateMetadatagenerateViewport内のparams
  • page.js内のsearchParams

移行を容易にするため、これらのAPIは一時的に同期的にアクセスできますが、次のメジャーバージョンまで開発時と本番環境で警告が表示されます。移行を自動化するコーモッドが利用可能です:

npx @next/codemod@canary next-async-request-api .

コーモッドで完全に移行できないケースについては、アップグレードガイドをお読みください。新しいAPIへのNext.jsアプリケーションの移行方法のも提供しています。

Server Actionsのセキュリティ強化

Server Actionsは、クライアントから呼び出せるサーバーサイド関数です。ファイルの先頭に'use server'ディレクティブを追加し、async関数をエクスポートすることで定義されます。

Server Actionやユーティリティ関数がコード内でインポートされていなくても、公開可能なHTTPエンドポイントとしてアクセスできます。この動作は技術的には正しいですが、意図しない関数の公開につながる可能性があります。

セキュリティを向上させるため、以下の強化を導入しました:

  • デッドコード削除: 未使用のServer ActionsはクライアントサイドJavaScriptバンドルにIDが公開されず、バンドルサイズの削減とパフォーマンス向上につながります。
  • セキュアなアクションID: Next.jsは現在、クライアントが参照してServer Actionを呼び出すための推測不可能で非決定論的なIDを作成します。これらのIDはビルド間で定期的に再計算され、セキュリティが強化されます。
// app/actions.js
'use server';
 
// このアクションはアプリケーションで**使用されている**ため、Next.jsは
// クライアントが参照してServer Actionを呼び出すためのセキュアなIDを作成します。
export async function updateUserAction(formData) {}
 
// このアクションはアプリケーションで**使用されていない**ため、Next.jsは
// `next build`中にこのコードを自動的に削除し、公開エンドポイントを作成しません。
export async function deleteUserAction(formData) {}

Server Actionsは公開HTTPエンドポイントとして扱うべきです。Server Actionsのセキュリティ保護について詳しく学んでください。

静的ルートインジケーター

Next.jsは現在、開発中に静的ルートインジケーターを表示し、どのルートが静的または動的かを識別するのに役立ちます。この視覚的合図により、ページがどのようにレンダリングされるかを理解することでパフォーマンスを最適化しやすくなります。

next build出力を使用して、すべてのルートのレンダリング戦略を表示することもできます。

この更新は、Next.jsの可観測性を向上させる継続的な取り組みの一部であり、開発者がアプリケーションを監視、デバッグ、最適化しやすくします。専用の開発者ツールにも取り組んでおり、詳細は近日中に発表されます。

無効にできる静的ルートインジケーターについて詳しく学んでください。

<Form>コンポーネント

新しい<Form>コンポーネントは、プリフェッチクライアントサイドナビゲーション、プログレッシブエンハンスメントでHTML<form>要素を拡張します。

これは、検索フォームのように新しいページにナビゲートするフォームに便利です。

import Form from 'next/form';
 
export default function Page() {
  return (
    <Form action="/search">
      <input name="query" />
      <button type="submit">送信</button>
    </Form>
  );
}

<Form>コンポーネントには以下が含まれます:

  • プリフェッチ: フォームが表示されると、レイアウトローディングUIがプリフェッチされ、ナビゲーションが高速化されます。
  • クライアントサイドナビゲーション: 送信時、共有レイアウトとクライアントサイドの状態が保持されます。
  • プログレッシブエンハンスメント: JavaScriptがまだ読み込まれていない場合でも、フルページナビゲーションでフォームが機能します。

以前は、これらの機能を実現するために多くの手動ボイラープレートが必要でした。例えば:

// 注:デモンストレーション目的で簡略化されています。
// 本番コードでの使用は推奨されません。
 
'use client'
 
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
 
export default function Form(props) {
  const action = props.action
  const router = useRouter()
 
  useEffect(() => {
    // フォームターゲットがURLの場合、プリフェッチ
    if (typeof action === 'string') {
      router.prefetch(action)
    }
  }, [action, router])
 
  function onSubmit(event) {
    event.preventDefault()
 
    // フォームフィールドを取得し、データをURLエンコードして`router.push`をトリガー
    const formData = new FormData(event.currentTarget)
    const data = new URLSearchParams()
 
    for (const [name, value] of formData) {
      data.append(name, value as string)
    }
 
    router.push(`${action}?${data.toString()}`)
  }
 
  if (typeof action === 'string') {
    return <form onSubmit={onSubmit} {...props} />
  }
 
  return <form {...props} />
}

<Form>コンポーネントについて詳しく学ぶ。

next.config.tsのサポート

Next.jsは現在、TypeScriptのnext.config.tsファイルタイプをサポートし、オートコンプリートとタイプセーフなオプションのためにNextConfigタイプを提供します:

import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  /* 設定オプションをここに記述 */
};
 
export default nextConfig;

Next.jsのTypeScriptサポートについて詳しく学ぶ。

instrumentation.js(安定版)

instrumentationファイルとregister() APIにより、ユーザーはNext.jsサーバーのライフサイクルにアクセスしてパフォーマンスを監視し、エラーの原因を追跡し、OpenTelemetryなどの可観測性ライブラリと深く統合できます。

この機能は現在安定版であり、experimental.instrumentationHook設定オプションは削除できます。

さらに、Sentryと協力して、新しいonRequestErrorフックを設計しました。これを使用すると:

  • サーバーでスローされたすべてのエラーに関する重要なコンテキストをキャプチャできます:
    • ルーター:Pages RouterまたはApp Router
    • サーバーコンテキスト:Server Component、Server Action、Route Handler、またはMiddleware
  • エラーをお気に入りの可観測性プロバイダーに報告できます。
export async function onRequestError(err, request, context) {
  await fetch('https://...', {
    method: 'POST',
    body: JSON.stringify({ message: err.message, request, context }),
    headers: { 'Content-Type': 'application/json' },
  });
}
 
export async function register() {
  // お気に入りの可観測性プロバイダーSDKを初期化
}

onRequestError関数について詳しく学ぶ。

開発とビルドの改善

Server Components HMR

開発中、Server Componentsは保存時に再実行されます。つまり、APIエンドポイントやサードパーティサービスへのfetchリクエストも呼び出されます。

ローカル開発のパフォーマンスを向上させ、課金対象のAPIコールの潜在的なコストを削減するため、Hot Module Replacement(HMR)が以前のレンダリングからのfetchレスポンスを再利用できるようにしました。

Server Components HMRキャッシュについて詳しく学ぶ。

App Routerの静的生成の高速化

特にネットワークリクエストが遅いページのビルド時間を改善するため、静的生成を最適化しました。

以前は、静的最適化プロセスでページを2回レンダリングしていました—1回目はクライアントサイドナビゲーション用のデータ生成、2回目は初期ページ訪問用のHTMLレンダリングです。現在は最初のレンダリングを再利用し、2回目のパスを削除することで作業負荷とビルド時間を削減しました。

さらに、静的生成ワーカーはページ間でfetchキャッシュを共有するようになりました。fetch呼び出しがキャッシュをオプトアウトしない場合、その結果は同じワーカーが処理する他のページで再利用されます。これにより、同じデータに対するリクエスト数が削減されます。

高度な静的生成制御(実験的機能)

高度なユースケース向けに、静的生成プロセスをより細かく制御できる実験的サポートを追加しました。

これらのオプションはリソース使用量の増加や、並列処理の増加によるメモリ不足エラーの可能性があるため、特別な要件がない限り現在のデフォルト設定を使用することを推奨します。

const nextConfig = {
  experimental: {
	  // ビルドが失敗する前に、Next.jsがページ生成の失敗を何回再試行するか
    staticGenerationRetryCount: 1
    // 1ワーカーあたりに処理されるページ数
    staticGenerationMaxConcurrency: 8
    // 新しいエクスポートワーカーを起動する最小ページ数
    staticGenerationMinPagesPerWorker: 25
  },
}
 
export default nextConfig;

静的生成オプションについて詳しく学ぶ。

セルフホスティングの改善

アプリケーションをセルフホスティングする場合、Cache-Controlディレクティブをより細かく制御する必要があるかもしれません。

一般的なケースとして、ISRページに対して送信されるstale-while-revalidate期間の制御があります。2つの改善を実装しました:

  1. next.configexpireTime値を設定できるようになりました。これは以前はexperimental.swrDeltaオプションでした。
  2. デフォルト値を1年に更新し、ほとんどのCDNが意図した通りにstale-while-revalidateセマンティクスを完全に適用できるようにしました。

また、カスタムのCache-Control値をデフォルト値で上書きしなくなり、完全な制御が可能になり、あらゆるCDN設定との互換性が確保されました。

最後に、セルフホスティング時の画像最適化を改善しました。以前は、Next.jsサーバーで画像を最適化するためにsharpをインストールすることを推奨していましたが、この推奨が見逃されることがありました。Next.js 15では、next startを使用する場合やスタンドアロン出力モードで実行する場合、手動でsharpをインストールする必要がなくなりました - Next.jsが自動的にsharpを使用します。

詳細については、Next.jsのセルフホスティングに関する新しいデモとチュートリアル動画をご覧ください。

ESLint 9のサポート

Next.js 15では、2024年10月5日にサポート終了となるESLint 8に続き、ESLint 9のサポートを導入しました。

スムーズな移行を確保するため、Next.jsは後方互換性を維持しており、ESLint 8または9のどちらも引き続き使用できます。

ESLint 9にアップグレードし、新しい設定形式をまだ採用していないことが検出された場合、Next.jsは自動的にESLINT_USE_FLAT_CONFIG=falseというエスケープハッチを適用して移行を容易にします。

さらに、next lintを実行する際に、—ext—ignore-pathなどの非推奨オプションが削除されます。ESLintは最終的にESLint 10でこれらの古い設定を許可しなくなるため、早めに移行を開始することをお勧めします。

これらの変更の詳細については、移行ガイドを確認してください。

この更新の一環として、React Hooksの使用に関する新しいルールを導入するeslint-plugin-react-hooksv5.0.0にアップグレードしました。すべての変更は[email protected]の変更履歴で確認できます。

その他の変更

  • RC 1のブログ記事で以前説明されたすべての変更
  • 【破壊的変更】 App Routerでexport const runtime = "experimental-edge"をエクスポートすることを非推奨にしました。ユーザーはexport const runtime = "edge"に切り替える必要があります。この変更を行うためのコードモッドを追加しました(PR
  • 【破壊的変更】 レンダリング中にrevalidateTagrevalidatePathを呼び出すとエラーがスローされるようになりました(PR
  • 【破壊的変更】 instrumentation.jsmiddleware.jsファイルでベンダー化されたReactパッケージを使用するようになりました(PR
  • 【破壊的変更】 必要なNode.jsの最小バージョンが18.18.0に更新されました(PR
  • 【破壊的変更】 next/dynamic:非推奨のsuspenseプロパティが削除され、App Routerでコンポーネントが使用された場合、空のSuspense境界が挿入されなくなりました(PR
  • 【破壊的変更】 Edge Runtimeでモジュールを解決する際、workerモジュール条件が適用されなくなりました(PR
  • 【破壊的変更】 Server Componentsでnext/dynamicssr: falseオプションの併用が禁止されました(PR
  • 【改善】 outputFileTracingRootoutputFileTracingIncludesoutputFileTracingExcludesが実験的機能から安定版に昇格しました(PR
  • 【改善】 ツリーの深い位置にあるCSSモジュールファイルとグローバルCSSファイルのマージを回避するようになりました(PR
  • 【改善】 キャッシュハンドラーをNEXT_CACHE_HANDLER_PATH環境変数で指定できるようになりました(PR
  • 【改善】 Pages RouterがReact 18とReact 19の両方をサポートするようになりました(PR
  • 【改善】 エラーオーバーレイに、インスペクタが有効な場合にNode.js Inspector URLをコピーするボタンが表示されるようになりました(PR
  • 【改善】 App Routerのクライアントプリフェッチでpriority属性を使用するようになりました(PR
  • 【改善】 Next.jsがApp RouterでNext.js内部エラーを再スローするためのunstable_rethrow関数を提供するようになりました(PR
  • 【改善】 unstable_afterが静的ページで使用できるようになりました(PR
  • 【改善】 SSR中にnext/dynamicコンポーネントが使用された場合、チャンクがプリフェッチされるようになりました(PR
  • 【改善】 App RouterでesmExternalsオプションがサポートされるようになりました(PR
  • 【改善】 デバッグ目的でnext buildNODE_ENV=developmentを併用できるようにするexperimental.allowDevelopmentBuildオプションが追加されました(PR
  • 【改善】 Pages RouterでServer Action変換が無効になりました(PR
  • 【改善】 ビルドワーカーが終了した際にビルドがハングするのを防ぐようになりました(PR
  • 【改善】 Server Actionからのリダイレクト時に再検証が正しく適用されるようになりました(PR
  • 【改善】 Edge Runtimeで並列ルートの動的パラメータが正しく処理されるようになりました(PR
  • 【改善】 静的ページが初期ロード後にstaleTimeを尊重するようになりました(PR
  • 【改善】 メモリリーク修正を含むvercel/ogが更新されました(PR
  • 【改善】 APIモック用のmswなどのパッケージを使用できるようにパッチタイミングが更新されました(PR

コントリビューター

Next.jsは、Vercelのコアチームと3,000人以上の個人開発者の共同作業の結果です。このリリースは以下の方々によってもたらされました:

@huozhi, @shuding, @wyattjoh, @PaulAsjes, @mcnaveen, @timneutkens, @stipsan, @aktoriukas, @sirTangale, @greatvivek11, @sokra, @anatoliik-lyft, @wbinnssmith, @coltonehrman, @hungdoansy, @kxlow, @ztanner, @manovotny, @leerob, @ryota-murakami, @ijjk, @pnutmath, @feugy, @Jeffrey-Zutt, @wiesson, @eps1lon, @devjiwonchoi, @Ethan-Arrowood, @kenji-webdev, @domdomegg, @samcx, @Jaaneek, @evanwinter, @kdy1, @balazsorban44, @feedthejim, @ForsakenHarmony, @kwonoj, @delbaoliveira, @xiaohanyu, @dvoytenko, @bobaaaaa, @bgw, @gaspar09, @souporserious, @unflxw, @kiner-tang, @Ehren12, @EffectDoplera, @IAmKushagraSharma, @Auxdible, @sean-rallycry, @jeanmax1me, @unstubbable, @NilsJacobsen, @adiguno, @ryan-nauman, @zsh77, @KagamiChan, @steveluscher, @MehfoozurRehman, @vkryachko, @chentsulin, @samijaber, @begalinsaf, @FluxCapacitor2, @lukahartwig, @brianshano, @pavelglac, @styfle, @symant233, @HristovCodes, @karlhorky, @jonluca, @jonathan-ingram, @mknichel, @sopranopillow, @Gomah, @imddc, @notrab, @gabrielrolfsen, @remorses, @AbhiShake1, @agadzik, @rishabhpoddar, @rezamauliadi, @IncognitoTGT, @webtinax, @BunsDev, @nisabmohd, @z0n, @bennettdams, @joeshub, @n1ckoates, @srkirkland, @RiskyMH, @coopbri, @okoyecharles, @diogocapela, @dnhn, @typeofweb, @davidsa03, @imranolas, @lubieowoce, @maxhaomh, @mirasayon, @blvdmitry, @hwangstar156, @lforst, @emmerich, @christian-bromann, @Lsnsh, @datner, @hiro0218, @flybayer, @ianmacartney, @ypessoa, @ryohidaka, @icyJoseph, @Arinji2, @lovell, @nsams, @Nayeem-XTREME, @JamBalaya56562, @Arindam200, @gaojude, @qqww08, @todor0v, @tokkiyaa, @arlyon, @lorensr, @Juneezee, @Sayakie, @IGassmann, @bosconian-dynamics, @phryneas, @akazwz, @atik-persei, @shubh73, @alpedia0, @chogyejin, @notomo, @ArnoldVanN, @dhruv-kaushik, @kevva, @Kahitar, @anay-208, @boris-szl, @devnyxie, @LorisSigrist, @M-YasirGhaffar, @Lada496, @kippmr, @torresgol10, @pkiv, @Netail, @jontewks, @ArnaudFavier, @chrisjstott, @mratlamwala, @mayank1513, @karlkeefer, @kshehadeh, @Marukome0743, @a89529294, @anku255, @KeisukeNagakawa, @andrii-bodnar, @aldosch, @versecafe, @steadily-worked, @cfrank, @QiuranHu, @farsabbutt, @joostmeijles, @saltcod, @archanaagivale30, @crutchcorn, @crebelskydico, @Maaz-Ahmed007, @jophy-ye, @remcohaszing, @JoshuaKGoldberg, @creativoma, @GyoHeon, @SukkaW, @MaxLeiter, @neila-a, @stylessh, @Teddir, @ManuLpz4, @Julian-Louis, @syi0808, @mert-duzgun, @amannn, @MonstraG, @hamirmahal, @tariknh, @Kikobeats, @LichuAcu, @Kuboczoch, @himself65, @Sam-Phillemon9493, @Shruthireddy04, @Hemanshu-Upadhyay, @timfuhrmann, @controversial, @pathliving, @mischnic, @mauroaccornero, @NavidNourani, @allanchau, @ekremkenter, @yurivangeffen, @gnoff, @darthmaim, @gdborton, @Willem-Jaap, @KentoMoriwaki, @TrevorSayre, @marlier, @Luluno01, @xixixao, @domin-mnd, @niketchandivade, @N2D4, @kjugi, @luciancah, @mud-ali, @codeSTACKr, @luojiyin1987, @mehmetozguldev, @ronanru, @tknickman, @joelhooks, @khawajaJunaid, @rubyisrust, @abdull-haseeb, @bewinsnw, @housseindjirdeh, @li-jia-nan, @aralroca, @s-ekai, @ah100101, @jantimon, @jordienr, @iscekic, @Strift, @slimbde, @nauvalazhar, @HughHzyb, @guisehn, @wesbos, @OlyaPolya, @paarthmadan, @AhmedBaset, @dineshh-m, @avdeev, @Bhavya031, @MildTomato, @Bjornnyborg, @amikofalvy, @yosefbeder, @kjac, @woutvanderploeg, @Ocheretovich, @ProchaLu, @luismiramirez, @omahs, @theoludwig, @abhi12299, @sommeeeer, @lumirlumir, @royalfig, @iampoul, @molebox, @txxxxc, @zce, @mamuso, @kahlstrm, @vercel-release-bot, @zhawtof, @PapatMayuri, @PlagueFPS, @IDNK2203, @jericopulvera, @liby, @CannonLock, @timfish, @whatisagi, @none23, @haouvw, @Pyr33x, @SouthLink, @frydj, @CrutchTheClutch, @sleevezip, @r34son, @yunsii, @md-rejoyan-islam, @kartheesan05, @nattui, @KonkenBonken, @weicheng95, @brekk, @Francoscopic, @B33fb0n3, @ImDR, @nurullah, @hdodov, @ebCrypto, @soedirgo, @floriangosse, @Tim-Zj, @raeyoung-kim, @erwannbst, @DerTimonius, @hirotomoyamada, @Develliot, @chandanpasunoori, @vicb, @ankur-dwivedi, @kidonng, @baeharam, @AnaTofuZ, @coderfin, @xugetsu, @alessiomaffeis, @kutsan, @jordyfontoura, @sebmarkbage, @tranvanhieu01012002, @jlbovenzo, @Luk-z, @jaredhan418, @bangseongbeom, @penicillin0, @neoFinch, @DeepakBalaraman, @Manoj-M-S, @Unsleeping, @lonr, @Aerilym, @ytori, @acdlite, @actopas, @n-ii-ma, @adcichowski, @mobeigi, @JohnGemstone, @jjm2317の方々、協力いただき誠にありがとうございました!