Backブログに戻る

Next.js 9.5 リリース

Next.js 9.5では、安定版インクリメンタル静的再生成、カスタムベースパス、リダイレクトとリライト、Webpack 5ベータ版などが導入されました!

本日、Next.js 9.5のリリースを発表します。主な新機能は以下の通りです:

安定版インクリメンタル静的再生成

Next.jsは9.3で静的サイト生成メソッドを導入しました。その目的は明確でした:静的の利点(常に高速、常にオンライン、グローバルにレプリケート可能)を得つつ、Next.jsが得意とする動的データの優れたサポートを提供することです。

この両方の利点を得るため、Next.jsはインクリメンタル静的生成を導入し、サイト構築後に静的コンテンツを更新できるようにしました。getStaticPathsfallback: trueオプションを使用することで、新しい静的ページをランタイム時に登録できます。

Next.jsはこの方法で、データセットのサイズに関係なく、オンデマンドで無限のページを静的に事前レンダリングできます。

本日、インクリメンタル静的再生成一般提供を発表します。これは、トラフィックが入ってくる際にバックグラウンドで再レンダリングすることで、既存のページを更新するメカニズムです。

stale-while-revalidateにインスパイアされたこのバックグラウンド再生成は、トラフィックが中断なく提供されることを保証し、常に静的ストレージから提供され、新しく構築されたページは生成が完了した後にのみプッシュされます。

export async function getStaticProps() {
  return {
    props: await getDataFromCMS(),
    // ページの再生成を試みます:
    // - リクエストが入った時
    // - 最大1秒に1回
    revalidate: 1,
  };
}

revalidateフラグは、キャッシュスタンピードを防ぐために、最大1回の生成が行われる秒数です。

従来のSSRとは異なり、インクリメンタル静的再生成により、静的の利点を保持できます:

  • レイテンシのスパイクなし。ページは一貫して高速に提供されます。
  • ページがオフラインになることはありません。バックグラウンドのページ再生成が失敗しても、古いページは変更されません。
  • データベースとバックエンドの負荷が低い。ページは最大で同時に1回のみ再計算されます。

インクリメンタル機能(ページの追加と遅延更新)とプレビューモードは、現在安定しており、next startVercelエッジプラットフォームの両方で完全にサポートされています。

この新機能を紹介するために、特定のGitHubイシューのさまざまなリアクションのカウントを表示する静的ページを再生成するデモを作成しました: https://reactions-demo.vercel.app/

絵文字リアクション後の最初の訪問後、バックグラウンドで新しいページ生成が開始されます。すべてのリクエストは静的キャッシュから提供されます。

絵文字リアクション後の最初の訪問後、バックグラウンドで新しいページ生成が開始されます。すべてのリクエストは静的キャッシュから提供されます。

次に、2つの追加のインクリメンタル静的生成機能に対応するための補足RFCに取り組みます:

  • 複数のページを一度に再生成および無効化(ブログインデックスと特定のブログ投稿など)
  • イベント(CMSウェブフックなど)をリスニングして、ユーザートラフィックの前に再生成

詳細については、getStaticPropsドキュメントをご覧ください。

カスタマイズ可能なベースパス

Next.jsプロジェクトは常にドメインのルートから提供されるわけではありません。Next.jsプロジェクトを/docsなどのサブパスでホストし、Next.jsプロジェクトがドメインのその部分のみをカバーするようにしたい場合があります。

これまでも可能でしたが、かなりの追加設定が必要でした。例えば、すべての<Link>にプレフィックスを追加したり、Next.jsが正しいパスからJavaScriptバンドルを提供していることを確認したりする必要がありました。

この問題に対処するため、新しい設定オプションを導入します。basePathを使用すると、ドメインのサブパスでNext.jsプロジェクトを簡単にホストできます。

basePathの使用を開始するには、next.config.jsに追加します:

next.config.js
module.exports = {
  basePath: '/docs',
};

basePathを設定すると、プロジェクトは自動的に指定されたパスからルーティングされます。この場合は/docsです。

next/linkまたはnext/routerでプロジェクト内の他のページにリンクする場合、basePathは自動的にプレフィックスとして追加されます。これにより、プロジェクトを変更せずにbasePathを変更できます。

例として、next/linkを使用して別のページにルーティングする場合:

import Link from 'next/link';
 
export default function HomePage() {
  return (
    <>
      <Link href="/documentation-page">
        <a>Documentation page</a>
      </Link>
    </>
  );
}

この方法でnext/linkを使用すると、Webブラウザに次のHTMLがレンダリングされます:

<a href="/docs/documentation-page">Documentation page</a>

詳細については、basePathドキュメントをご覧ください。

リライト、リダイレクト、ヘッダーのサポート

リライト

Next.jsプロジェクトを構築する際、特定のルートを別のURLにプロキシしたい場合があります。例えば、Next.jsをスタックに段階的に導入する場合、Next.jsプロジェクトに存在するページをルーティングし、マッチしなかったものを移行中の古いプロジェクトにルーティングしたいでしょう。

Next.js 9.5では、rewritesという新しい設定オプションを導入します。これにより、受信リクエストパスを別の宛先パス(外部URLを含む)にマッピングできます。

例えば、特定のルートをexample.comにリライトしたい場合:

next.config.js
module.exports = {
  async rewrites() {
    return [
      { source: '/backend/:path*', destination: 'https://example.com/:path*' },
    ];
  },
};

この場合、/backend以下のすべてのパスはexample.comにルーティングされます。

Next.jsプロジェクトのルートがマッチしたかどうかを確認し、マッチしなかった場合に以前のプロジェクトにリライトすることもできます。これはNext.jsの段階的な導入に非常に役立ちます:

module.exports = {
  async rewrites() {
    return [
      // プロキシを試みる前にNext.jsプロジェクトのルートがマッチするか確認
      {
        source: '/:path*',
        destination: '/:path*',
      },
      {
        source: '/:path*',
        destination: `https://example.com/:path*`,
      },
    ];
  },
};

この場合、最初にすべてのパスをマッチさせます。マッチしない場合、以前のプロジェクトであるexample.comにプロキシします。

rewrites機能の詳細については、リライトドキュメントをご覧ください。

リダイレクト

ほとんどのWebサイトでは、少なくともいくつかのリダイレクトが必要です。特にプロジェクトルートの構造を変更する場合です。例えば、/blog/newsに移動する場合などです。

以前は、Next.jsプロジェクトにリダイレクトのリストを設定するには、カスタムサーバーをセットアップするか、ルートに設定されたリダイレクトを確認するためのカスタム_errorページが必要でした。しかし、これにはサーバーを持つことで重要な静的およびサーバーレス最適化が無効になるか、十分にエルゴノミックではありませんでした。

Next.js 9.5から、next.config.jsredirectsキーの下にリダイレクトのリストを作成できるようになりました:

next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/about',
        destination: '/',
        permanent: true,
      },
    ];
  },
};

redirects機能の詳細については、リダイレクトドキュメントをご覧ください。

ヘッダー

Next.jsでは、静的生成 (Static Generation) とサーバーサイドレンダリング (SSR) の両方を使用するハイブリッドプロジェクトを構築できます。サーバーサイドレンダリングでは、受信リクエストに対してヘッダーを設定することが可能です。これまで静的ページではヘッダーの設定ができませんでした。

現在、next.config.jsheaders プロパティが導入され、すべてのNext.jsルートに適用されます:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Feature-Policy',
            // マイクと位置情報を無効化
            value: "microphone 'none'; geolocation 'none'",
          },
        ],
      },
    ];
  },
};

headers オプションでは、Feature-PolicyContent-Security-Policy など、一般的に必要なヘッダーを設定できます。

headers 機能の詳細については、ヘッダードキュメントをご覧ください。

URL末尾のスラッシュをオプションに

Next.jsが3年前に導入されたとき、デフォルトの動作は末尾にスラッシュがあるすべてのURLが404ページを返すようになっていました。

効果的ではありましたが、この動作を変更できるようにしてほしいという要望がありました。例えば、既存のプロジェクトをNext.jsに移行する際に、以前から常に末尾のスラッシュが強制されていた場合などです。

Next.js 9.5では、next.config.jstrailingSlash という新しいオプションが導入されました。

この新しいオプションにより、Next.jsが自動的に末尾のスラッシュの動作を処理します:

  • 末尾にスラッシュがあるURLをスラッシュなしのURLに自動的にリダイレクトします(例: /about/ から /about へ)
  • trailingSlashtrue に設定されている場合、スラッシュなしのURLはスラッシュありのURLにリダイレクトされます(例: /about から /about/ へ)
  • next/link が自動的にスラッシュを追加/削除し、不要なリダイレクトを防ぎます
next.config.js
module.exports = {
  // 末尾のスラッシュを強制(デフォルト値はスラッシュなし=false)
  trailingSlash: true,
};

trailingSlash 機能の詳細については、trailingSlashドキュメントをご覧ください

ページバンドルの永続的キャッシュ

Next.jsでページを作成する際、すべてのスクリプトバンドル、CSSスタイルシート、HTMLの生成は完全に自動化され、開発者から抽象化されています。Next.js 9.5以前に生成された <script> タグを調べると、次のようなパターンのURLになっていることに気づくでしょう:

/_next/static/ovgxWYrvKyjnlM15qtz7h/pages/about.js

上記のパスセグメント ovgxWYrvKyjnlM15qtz7h は、私たちが ビルドID と呼んでいたものです。これらのファイルはエッジやユーザーのマシンで簡単にキャッシュ可能でしたが、アプリを再ビルドするとビルドIDが変更され、すべてのキャッシュが無効化されていました。

ほとんどのプロジェクトではこのトレードオフは問題ありませんでしたが、変更のなかったページに対してブラウザキャッシュを無効化しないように、この動作をさらに最適化したいと考えました。

Google Chromeチームと共同で開発されたNext.js 9.2の改良されたコード分割戦略の導入は、Next.jsのページバンドル生成に対するこれらの改善の基礎となりました。

Next.js 9.5以降、すべてのページJavaScriptバンドルはビルドIDの代わりにコンテンツハッシュを使用します。これにより、デプロイ間で変更のなかったページは、再度ダウンロードする必要なくブラウザとエッジキャッシュに残ることができます。

対照的に、これらの変更後のURLパターンは次のようになります:

/_next/static/chunks/pages/about.qzfS4o5gIEXRME6sTEahL.js

グローバルなビルドIDの代わりに、qzfS4o5gIEXRME6sTEahL の部分は about.js バンドルの決定論的ハッシュであり、サイトのそのセクションのコードが変更されない限り安定しています。さらに、Next.jsが自動的に設定する Cache-Control: public,max-age=31536000,immutable によって、再デプロイ後も長期間キャッシュされます

Fast Refreshの機能強化

私たちはNext.js 9.4でFast Refreshを導入しました。これはReactコンポーネントへの編集に対して即時のフィードバックを提供する新しいホットリロード体験です。

Next.js 9.5では、Fast Refreshの実装をさらに洗練させ、成功に必要なツールを提供します:

  • 理解しやすいエラー: すべてのコンパイルエラーとランタイムエラーが更新され、コードフレームを含む関連情報のみを表示 するようになりました。
  • コンポーネント状態を保持するための開発時ヒント: Next.jsは現在、Fast Refreshが可能な限り多くのシナリオでコンポーネント状態を保持するための役立つヒントを提供します。Next.jsが提供する各ヒントは完全に実践可能で、前後の例が付随しています!
  • コンポーネント状態がリセットされる際の警告: ファイルが編集された後にNext.jsがコンポーネント状態を保持できない場合、詳細な警告が表示されるようになりました。この警告は、プロジェクトがコンポーネント状態をリセットしなければならなかった理由を診断するのに役立ち、修正してFast Refreshを最大限に活用できるようにします。
  • 新しいドキュメント: 詳細なドキュメントを追加し、Fast Refreshが何であるか、どのように動作するか、何を期待すべきかを説明しています! このドキュメントでは、エラー回復の仕組みを説明することで、Fast Refreshをより効果的に活用する方法も学べます。
  • ユーザーコードのトラブルシューティングガイド: 新しいドキュメントには、一般的なトラブルシューティング手順とヒントも含まれており、開発中にFast Refreshを最大限に活用する方法がわかります。

本番環境でのReactプロファイリング

Reactは以前からProfiler APIを導入しており、Reactコンポーネントのパフォーマンス問題を追跡できます。この機能は開発環境では自動的に動作しますが、本番環境でプロファイリングするには別バージョンのReactDOMを使用する必要がありました。

Next.js 9.5では、next build--profile フラグを使用してReactの本番プロファイリングを有効化できるようになりました:

next build --profile

その後、開発環境と同じ方法でプロファイラーを使用できます。

Reactのプロファイリングについて詳しく知りたい場合は、ReactチームによるReact Profilerの投稿をお読みください。この機能を貢献してくれたTODOrTotev@darshkpatelに特に感謝します。

オプションのキャッチオールルート

Next.js 9.2でキャッチオールダイナミックルートのサポートが追加され、さまざまなユースケースでコミュニティに広く採用されました。キャッチオールルートは、ヘッドレスCMS、GraphQL API、ファイルシステムなどによって駆動される高度に動的なルーティング構造を作成する柔軟性を提供します。

フィードバックを聞く中で、ユーザーがルートの最上位レベルもマッチさせたいという要望があることがわかりました。今日、これらの高度なシナリオ向けにオプションのキャッチオールダイナミックルートを発表できることを嬉しく思います。

オプションのキャッチオールルートを作成するには、[[...slug]] 構文を使用してページを作成します。

例えば、pages/blog/[[...slug]].js/blog だけでなく、その下の任意のルート(/blog/a/blog/a/b/c など)にもマッチします。

キャッチオールルートと同様に、slugルータークエリオブジェクト内でパスの部分の配列として提供されます。したがって、/blog/foo/bar というパスの場合、クエリオブジェクトは { slug: ['foo', 'bar'] } になります。/blog というパスの場合、クエリオブジェクトからslugキーが省略されます: { }

ドキュメントでオプションのキャッチオールルートについて詳しく学べます

Webpack 5サポート(ベータ版)

Webpack 5は現在ベータ版です。以下のような主要な改善が含まれています:

本日、Next.js向けのwebpack 5のベータ版提供を発表できることを嬉しく思います。

webpack 5を試すには、package.jsonYarn resolutionsを使用できます:

package.json
{
  "resolutions": {
    "webpack": "^5.0.0-beta.30"
  }
}

Webpack 5ベータは既にnextjs.orgvercel.comの本番環境に展開されています。段階的に試していただき、GitHubで発見したことを報告することをお勧めします。

コンパイルインフラの改善

webpack 5をサポートするために、Next.jsに特化したコンパイルパイプラインの多くを書き直しました:

  • Next.jsはもはや webpack-hot-middlewarewebpack-dev-middleware に依存せず、代わりにwebpackを直接使用し、Next.jsプロジェクトに特化して最適化します。これにより、よりシンプルなアーキテクチャと高速な開発コンパイルが実現します。
  • オンデマンドエントリ(開発中に訪問したページをその時点でコンパイルするNext.jsのシステム)も書き直され、私たちのユースケースに特化した新しいwebpack動作を活用することでさらに信頼性が高まりました。
  • React Fast RefreshとNext.jsエラーオーバーレイがwebpack 5と完全に互換性を持つようになりました
  • ディスクキャッシュは今後のベータリリースで有効になります。

後方互換性

私たちは常にNext.jsが以前のバージョンと後方互換性があることを保証するよう努めています。

Webpack 4は引き続き完全にサポートされます。webpackチームと緊密に連携して、webpack 4から5への移行が可能な限りスムーズになるように取り組んでいます。

Next.jsプロジェクトにカスタムwebpack設定がない場合、webpack 5を完全に活用するためにプロジェクトの変更は必要ありません。

重要: プロジェクトにカスタムwebpack設定がある場合、webpack 5に移行するためにいくつかの変更が必要になる可能性があります。移行手順に注意を払うか、将来のアップグレードをシームレスにするためにwebpack拡張の使用を最小限に抑えることをお勧めします。

macOSでのファイル監視の改善

最近、webpackでmacOS上でファイル監視がコードに数回変更を加えた後に停止する問題が見つかりました。更新を確認するには手動でプロジェクトを再起動する必要があり、数回変更を加えるとこのサイクルが繰り返されていました。

さらに、この問題はNext.jsプロジェクトだけでなく、webpack上に構築されたすべてのプロジェクトやフレームワークで発生することがわかりました。

数日間のデバッグの後、この問題の根本原因を、webpackが使用するファイル監視実装であるchokidar(Node.jsエコシステムで広く使用されているファイル監視実装)に突き止めました。

私たちはchokidarにパッチを送信してこの問題を修正しました。パッチがリリースされた後、Tobias Koppersと協力して新しいwebpackバージョンでこのパッチを展開しました。

この修正済みwebpackバージョンは、Next.js 9.5にアップグレードすると自動的に使用されます。

まとめ

Next.jsの採用が継続的に成長していることを嬉しく思います:

  • 1,200人以上の独立したコントリビューターがおり、9.4リリース以降135人以上の新しいコントリビューターが加わりました。
  • GitHubでは、プロジェクトが51,100回以上スターされました。

GitHub DiscussionsでNext.jsコミュニティに参加してください。Discussionsは、他のNext.jsユーザーとつながり、自由に質問したり作業を共有できるコミュニティスペースです。

例えば、プロジェクトURLを共有することから始めると良いでしょう。

貢献したいが方法がわからない場合は、Webpackサポートなどの実験的機能を試して、発見したことを報告することをお勧めします!

クレジット

このリリースを形作るのに役立った外部からのフィードバックや貢献を含め、コミュニティに感謝します。

このリリースの複数の機能に貢献した長年のNext.jsコミュニティメンバーであるJan Potomsに特に感謝します。

webpackの作者であるTobias Koppersに、Next.jsでのwebpack 5サポートの実現に協力していただいたことに特に感謝します。

このリリースは以下の方々の貢献によってもたらされました: @chandan-reddy-k, @Timer, @aralroca, @artemisart, @sospedra, @prateekbh, @Prioe, @Janpot, @merceyz, @ijjk, @PavelK27, @marbiano, @MichelleLucero, @thorsten-stripe, @TODOrTotev, @Skn0tt, @lfades, @timneutkens, @akhila-ariyachandra, @chibicode, @rafaelalmeidatk, @kirill-konshin, @jamesvidler, @JeffersonBledsoe, @tylev, @jamesmosier, @filipemarins, @Remeic, @vvo, @timothyis, @jazibsawar, @coetry, @adam-zacharski, @danwilliams, @tywmick, @matamatanot, @goldins, @mvllow, @its-tayo, @sshyam-gupta, @wilbert-abreu, @sebastianbenz, @jaydenseric, @developit, @dylanjha, @darshkpatel, @spinks, @stefanprobst, @moh12594, @jasonmerino, @cristiand391, @HyunSangHan, @mcsdevv, @M1ck0, @hydRAnger, @alexej-d, @valmassoi, @motleydev, @eKhattak, @jpedroschmitz, @JerryGoyal, @bowen31337, @phillip055, @balazsorban44, @chuabingquan, @youhosi, @andresz1, @bell-steven, @areai51, @Wssn, @ndom91, @anthonyshort, @zxzl, @jbowes, @IamLizu, @PascalPixel, @ralphilius, @ysun62, @muslax, @elsigh, @AsherFoster, @botv, @tomdohnal, @christianalfoni, @tomasztunik, @gsimone, @illuminist, @jplew, @OskarKaminski, @RickyAbell, @steph-query, @ericgoe, @MalvinJay, @cristianbote, @Ashikpaul, @jensmeindertsma, @amorriscode, @abhik-b, @awareness481, @LukasPolak, @arvigeus, @romMidnight, @jackyef, @drumm2k, @kuldeepkeshwar, @bogy0, @Belco90, @wawjr3d, @tanmaylaud, @SarKurd, @kevinsproles, @dstotijn, @styfle, @blackwright, @BrunoBernardino, @heyAyushh, @Necmttn, @TrySound, @obedparla, @NyashaNziramasanga, @tonyspiro, @kukicado, @ceorourke, @MehediH, @robintom, @karlhorky, @tcK1!