コンテンツにスキップ
ブログに戻る

2023年10月26日(木)

Next.js 14

投稿者

Next.js Confで発表したように、Next.js 14は最も注力したリリースであり、

  • Turbopack: App & Pages Routerで5,000のテストに合格
    • ローカルサーバーの起動が53%高速化
    • Fast Refreshによるコード更新が94%高速化
  • Server Actions (安定版): プログレッシブに強化されたミューテーション
    • キャッシュと再検証との統合
    • 単純な関数呼び出し、またはフォームでのネイティブな動作
  • Partial Prerendering (プレビュー): 高速な初期静的レスポンスと動的コンテンツのストリーミング
  • Next.js Learn (新規): App Router、認証、データベースなどを教える無料コース。

今すぐアップグレードするか、以下を参考に開始してください。

ターミナル
npx create-next-app@latest

Next.jsコンパイラー: ターボチャージ

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

以前は、この取り組みをサポートするために、next devとNext.jsの他の部分を書き直していました。その後、より段階的なアプローチに変更しました。これは、すべてのNext.js機能を最初にサポートすることに焦点を当て直したため、Rustベースのコンパイラーが間もなく安定することを意味します。

RustエンジンのTurbopackを使用して、next devの5,000件の統合テストが合格しています。これらのテストには、7年間のバグ修正と再現が含まれています。

大規模なNext.jsアプリケーションであるvercel.comでテストしたところ、以下の結果が得られました。

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

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

テストの100%が合格したら、今後のマイナーリリースでTurbopackを安定版に移行します。また、カスタム構成とエコシステムプラグインのためにwebpackの使用も引き続きサポートします。

テストの合格率はareweturboyet.comで確認できます。

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

Next.js 9では、API Routesが導入されました。これは、フロントエンドコードと並行してバックエンドエンドポイントをすばやく構築する方法です。

たとえば、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とonSubmitのようなイベントハンドラーを使用して、API Routeにfetchを作成できます。

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では、データミューテーションの作成における開発者のエクスペリエンスを簡素化したいと考えています。さらに、ユーザーのネットワーク接続が遅い場合や、低電力デバイスからフォームを送信する場合に、ユーザーエクスペリエンスを向上させたいと考えています。

Server Actions (安定版)

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

App Routerは、新しい機能を採用するためのフレームワークで安定しているReact canaryチャネルに基づいて構築されています。v14の時点で、Next.jsは安定したServer Actionsを含む最新のReact canaryにアップグレードしました。

Pages Routerの以前の例は1つのファイルに簡略化できます。

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>
  );
}

Server Actionsは、過去にサーバー中心のフレームワークを使用したことがある開発者にとってはなじみ深いもののはずです。フォームやFormData Web APIなどのWebの基本に基づいて構築されています。

フォームを介してServer Actionsを使用することはプログレッシブエンハンスメントに役立ちますが、必須ではありません。フォームなしで、関数として直接呼び出すこともできます。TypeScriptを使用する場合、これにより、クライアントとサーバー間で完全にエンドツーエンドのタイプセーフティが実現します。

データの変更、ページの再レンダリング、またはリダイレクトは、1回のネットワークラウンドトリップで実行でき、アップストリームプロバイダーが遅い場合でも、クライアントに正しいデータが表示されるようにします。さらに、同じルートで多数の異なるアクションを含む、さまざまなアクションを構成して再利用できます。

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

Server Actionsは、App Routerモデル全体に深く統合されています。

  • revalidatePath()またはrevalidateTag()でキャッシュされたデータを再検証できます
  • redirect()を使用して別のルートにリダイレクトできます
  • cookies()を使用してCookieを設定および読み取ることができます
  • useOptimistic()を使用して楽観的なUI更新を処理できます
  • useFormState()を使用してサーバーからのエラーをキャッチして表示できます
  • useFormStatus()を使用してクライアントにローディング状態を表示できます

Server Actionsを使用したフォームとミューテーションまたは、セキュリティモデルおよびサーバーコンポーネントとServer Actionsのベストプラクティスについて詳しく学習してください。

Partial Prerendering (プレビュー)

Next.js で開発中の、高速な初期静的レスポンスを備えた動的コンテンツ向けのコンパイラ最適化である、部分プリレンダリングのプレビューをお知らせします。

部分プリレンダリングは、サーバーサイドレンダリング(SSR)、静的サイト生成(SSG)、およびインクリメンタル静的再検証(ISR)に関する10年間の研究開発に基づいています。

動機

皆様からのフィードバックをいただいています。現在、考慮しなければならないランタイム、構成オプション、レンダリングメソッドが多すぎます。完全に動的でパーソナライズされたレスポンスをサポートしながら、静的な速度と信頼性を求めています。

グローバルでの優れたパフォーマンスとパーソナライゼーションは、複雑さを犠牲にすべきではありません。

私たちの課題は、開発者が学ぶための新しいAPIを導入することなく、既存のモデルを簡素化し、より優れた開発者エクスペリエンスを作成することでした。サーバーサイドコンテンツの部分的なキャッシュは存在していましたが、これらのアプローチは、私たちが目指す開発者エクスペリエンスとコンポーザビリティの目標を満たす必要があります。

部分プリレンダリングでは、新しいAPIを学習する必要はありません。

React Suspense をベースに構築

部分プリレンダリングは、Suspense境界によって定義されます。仕組みは次のとおりです。次の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 Suspense の fallback がプリレンダリングされます。

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

リクエストが行われると、静的な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 />は、ユーザーセッションを確認するためにcookiesから読み取るため、このコンポーネントは、静的なシェルと同じHTTPリクエストの一部としてストリーミングされます。追加のネットワークラウンドトリップは必要ありません。

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

最も細かい静的シェルを持つには、追加のSuspense境界を追加する必要がある場合があります。ただし、現在loading.jsを使用している場合、これは暗黙的なSuspense境界であるため、静的シェルを生成するために変更は必要ありません。

近日公開

部分プリレンダリングは現在開発中です。今後のマイナーリリースで、より多くのアップデートを共有します。

メタデータの改善

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

これらの meta タグが最初のページコンテンツとともに送信されるようにすることで、スムーズなユーザーエクスペリエンスを実現し、テーマカラーの変更やビューポートの変更によるレイアウトのずれによるページのちらつきを防ぐことができます。

Next.js 14 では、ブロッキングメタデータと非ブロッキングメタデータを分離しました。メタデータオプションのほんの一部分のみがブロッキングであり、非ブロッキングメタデータが部分的にプリレンダリングされたページが静的シェルを提供することを妨げないようにする必要があります。

次のメタデータオプションは非推奨となり、今後のメジャーバージョンで metadata から削除されます。

  • viewport: ビューポートの初期ズームとその他のプロパティを設定します。
  • colorScheme: ビューポートのサポートモード(ライト/ダーク)を設定します。
  • themeColor: ビューポートの周りのクロムでレンダリングする色を設定します。

Next.js 14 以降、これらのオプションを置き換える新しいオプションとして、viewport および generateViewport があります。その他のすべての metadata オプションは同じままです。

これらの新しいAPIは今日から採用を開始できます。既存の metadata オプションは引き続き機能します。

Next.js Learnコース

本日、Next.js Learn で、まったく新しい無料のコースをリリースします。このコースでは以下を教えます。

  • Next.js App Router
  • スタイリングとTailwind CSS
  • フォントと画像の最適化
  • レイアウトとページの作成
  • ページ間の移動
  • Postgresデータベースのセットアップ
  • サーバーコンポーネントを使用したデータのフェッチ
  • 静的および動的レンダリング
  • ストリーミング
  • 部分プリレンダリング(オプション)
  • 検索とページネーションの追加
  • データの変更
  • エラーの処理
  • アクセシビリティの向上
  • 認証の追加
  • メタデータの追加

Next.js Learnは、何百万人もの開発者にフレームワークの基礎について教えてきました。新しい追加に関するフィードバックをお待ちしています。コースを受講するには、nextjs.org/learn にアクセスしてください。

その他の変更点

  • 【破壊的変更】 最小Node.jsバージョンが 18.17 になりました
  • 【破壊的変更】 next-swc ビルドのWASMターゲットを削除 (PR)
  • 【破壊的変更】 next/font を優先して @next/font のサポートを終了 (Codemod)
  • 【破壊的変更】 ImageResponse のインポートを next/server から next/og に変更 (Codemod)
  • 【破壊的変更】 next export コマンドが削除され、代わりに output: 'export' 設定を使用 (ドキュメント)
  • 【非推奨】 next/imageonLoadingComplete が非推奨となり、代わりにonLoad が使用されるようになりました。
  • 【非推奨】 next/imagedomains が非推奨となり、代わりにremotePatterns が使用されるようになりました。
  • 【機能】 fetch キャッシュに関するより詳細なログを有効にできます (ドキュメント)
  • 【改善】 基本的な create-next-app アプリケーションの関数サイズが 80% 削減
  • 【改善】 開発中に edge ランタイムを使用する場合のメモリ管理を強化

貢献者

Next.js は、2,900人を超える個々の開発者、GoogleやMetaのような業界パートナー、そして Vercel のコアチームによる共同作業の成果です。コミュニティには、GitHub DiscussionsReddit、そしてDiscordでご参加ください。

このリリースは、以下のチームによって実現しました。

以下の皆様のご貢献に感謝いたします: @05lazy, @0xadada, @2-NOW, @aarnadlr, @aaronbrown-vercel, @aaronjy, @abayomi185, @abe1272001, @abhiyandhakal, @abstractvector, @acdlite, @adamjmcgrath, @AdamKatzDev, @adamrhunter, @ademilter, @adictonator, @adilansari, @adtc, @afonsojramos, @agadzik, @agrattan0820, @akd-io, @AkifumiSato, @akshaynox, @alainkaiser, @alantoa, @albertothedev, @AldeonMoriak, @aleksa-codes, @alexanderbluhm, @alexkirsz, @alfred-mountfield, @alpha-xek, @andarist, @Andarist, @andrii-bodnar, @andykenward, @angel1254mc, @anonrig, @anthonyshew, @AntoineBourin, @anujssstw, @apeltop, @aralroca, @aretrace, @artdevgame, @artechventure, @arturbien, @Aryan9592, @AviAvinav, @aziyatali, @BaffinLee, @Banbarashik, @bencmbrook, @benjie, @bennettdams, @bertho-zero, @bigyanse, @Bitbbot, @blue-devil1134, @bot08, @bottxiang, @Bowens20832, @bre30kra69cs, @BrennanColberg, @brkalow, @BrodaNoel, @Brooooooklyn, @brunoeduardodev, @brvnonascimento, @carlos-menezes, @cassidoo, @cattmote, @cesarkohl, @chanceaclark, @charkour, @charlesbdudley, @chibicode, @chrisipanaque, @ChristianIvicevic, @chriswdmr, @chunsch, @ciruz, @cjmling, @clive-h-townsend, @colinhacks, @colinking, @coreyleelarson, @Cow258, @cprussin, @craigwheeler, @cramforce, @cravend, @cristobaldominguez95, @ctjlewis, @cvolant, @cxa, @danger-ahead, @daniel-web-developer, @danmindru, @dante-robinson, @darshanjain-entrepreneur, @darshkpatel, @davecarlson, @David0z, @davidnx, @dciug, @delbaoliveira, @denchance, @DerTimonius, @devagrawal09, @DevEsteves, @devjiwonchoi, @devknoll, @DevLab2425, @devvspaces, @didemkkaslan, @dijonmusters, @dirheimerb, @djreillo, @dlehmhus, @doinki, @dpnolte, @Drblessing, @dtinth, @ducanhgh, @DuCanhGH, @ductnn, @duncanogle, @dunklesToast, @DustinsCode, @dvakatsiienko, @dvoytenko, @dylanjha, @ecklf, @EndangeredMassa, @eps1lon, @ericfennis, @escwxyz, @Ethan-Arrowood, @ethanmick, @ethomson, @fantaasm, @feikerwu, @ferdingler, @FernandVEYRIER, @feugy, @fgiuliani, @fomichroman, @Fonger, @ForsakenHarmony, @franktronics, @FSaldanha, @fsansalvadore, @furkanmavili, @g12i, @gabschne, @gaojude, @gdborton, @gergelyke, @gfgabrielfranca, @gidgudgod, @Gladowar, @Gnadhi, @gnoff, @goguda, @greatSumini, @gruz0, @Guilleo03, @gustavostz, @hanneslund, @HarshaVardhanReddyDuvvuru, @haschikeks, @Heidar-An, @heyitsuzair, @hiddenest, @hiro0218, @hotters, @hsrvms, @hu0p, @hughlilly, @HurSungYun, @hustLer2k, @iamarpitpatidar, @ianldgs, @ianmacartney, @iaurg, @ibash, @ibrahemid, @idoob, @iiegor, @ikryvorotenko, @imranbarbhuiya, @ingovals, @inokawa, @insik-han, @isaackatayev, @ishaqibrahimbot, @ismaelrumzan, @itsmingjie, @ivanhofer, @IvanKiral, @jacobsfletch, @jakemstar, @jamespearson, @JanCizmar, @janicklas-ralph, @jankaifer, @JanKaifer, @jantimon, @jaredpalmer, @javivelasco, @jayair, @jaykch, @Jeffrey-Zutt, @jenewland1999, @jeremydouglas, @JesseKoldewijn, @jessewarren-aa, @jimcresswell, @jiwooIncludeJeong, @jocarrd, @joefreeman, @JohnAdib, @JohnAlbin, @JohnDaly, @johnnyomair, @johnta0, @joliss, @jomeswang, @joostdecock, @Josehower, @josephcsoti, @josh, @joshuabaker, @JoshuaKGoldberg, @joshuaslate, @joulev, @jsteele-stripe, @JTaylor0196, @JuanM04, @jueungrace, @juliusmarminge, @Juneezee, @Just-Moh-it, @juzhiyuan, @jyunhanlin, @kaguya3222, @karlhorky, @kevinmitch14, @keyz, @kijikunnn, @kikobeats, @Kikobeats, @kleintorres, @koba04, @koenpunt, @koltong, @konomae, @kosai106, @krmeda, @kvnang, @kwonoj, @ky1ejs, @kylemcd, @labyrinthitis, @lachlanjc, @lacymorrow, @laityned, @Lantianyou, @leerob, @leodr, @leoortizz, @li-jia-nan, @loettz, @lorenzobloedow, @lubakravche, @lucasassisrosa, @lucasconstantino, @lucgagan, @LukeSchlangen, @LuudJanssen, @lycuid, @M3kH, @m7yue, @manovotny, @maranomynet, @marcus-rise, @MarDi66, @MarkAtOmniux, @martin-wahlberg, @masnormen, @matepapp, @matthew-heath, @mattpr, @maxleiter, @MaxLeiter, @maxproske, @meenie, @meesvandongen, @mhmdrioaf, @michaeloliverx, @mike-plummer, @MiLk, @milovangudelj, @Mingyu-Song, @mirismaili, @mkcy3, @mknichel, @mltsy, @mmaaaaz, @mnajdova, @moetazaneta, @mohanraj-r, @molebox, @morganfeeney, @motopods, @mPaella, @mrkldshv, @mrxbox98, @nabsul, @nathanhammond, @nbouvrette, @nekochantaiwan, @nfinished, @Nick-Mazuk, @nickmccurdy, @niedziolkamichal, @niko20, @nikolovlazar, @nivak-monarch, @nk980113, @nnnnoel, @nocell, @notrab, @nroland013, @nuta, @nutlope, @obusk, @okcoker, @oliviertassinari, @omarhoumz, @opnay, @orionmiz, @ossan-engineer, @patrick91, @pauek, @peraltafederico, @Phiction, @pn-code, @pyjun01, @pythagoras-yamamoto, @qrohlf, @raisedadead, @reconbot, @reshmi-sriram, @reyrodrigez, @ricardofiorani, @rightones, @riqwan, @rishabhpoddar, @rjsdnql123, @rodrigofeijao, @runjuu, @Ryan-Dia, @ryo-manba, @s0h311, @sagarpreet-xflowpay, @sairajchouhan, @samdenty, @samsisle, @sanjaiyan-dev, @saseungmin, @SCG82, @schehata, @Schniz, @sepiropht, @serkanbektas, @sferadev, @ShaunFerris, @shivanshubisht, @shozibabbas, @silvioprog, @simonswiss, @simPod, @sivtu, @SleeplessOne1917, @smaeda-ks, @sonam-serchan, @SonMooSans, @soonoo, @sophiebits, @souporserious, @sp00ls, @sqve, @sreetamdas, @stafyniaksacha, @starunaway, @steebchen, @stefanprobst, @steppefox, @steven-tey, @suhaotian, @sukkaw, @SukkaW, @superbahbi, @SuttonJack, @svarunid, @swaminator, @swarnava, @syedtaqi95, @taep96, @taylorbryant, @teobler, @Terro216, @theevilhead, @thepatrick00, @therealrinku, @thomasballinger, @thorwebdev, @tibi1220, @tim-hanssen, @timeyoutakeit, @tka5, @tknickman, @tomryanx, @trigaten, @tristndev, @tunamagur0, @tvthatsme, @tyhopp, @tyler-lutz, @UnknownMonk, @v1k1, @valentincostam, @valentinh, @valentinpolitov, @vamcs, @vasucp1207, @vicsantizo, @vinaykulk621, @vincenthongzy, @visshaljagtap, @vladikoff, @wherehows, @WhoAmIRUS, @WilderDev, @Willem-Jaap, @williamli, @wiredacorn, @wiscaksono, @wojtekolek, @ws-jm, @wxh06, @wyattfry, @wyattjoh, @xiaolou86, @y-tsubuku, @yagogmaisp, @yangshun, @yasath, @Yash-Singh1, @yigithanyucedag, @ykzts, @Yovach, @yutsuten, @yyuemii, @zek, @zekicaneksi, @zignis, and @zlrlyy