2020年7月27日(月)
Next.js 9.5
投稿者本日、Next.js 9.5を発表できることを嬉しく思います。主な機能は以下のとおりです。
- 安定したインクリメンタル静的再生成:デプロイ後、数ミリ秒で静的ページを再構築します
- カスタマイズ可能なベースパス:ドメインのサブパスでNext.jsプロジェクトを簡単にホストできます
- リライト、リダイレクト、ヘッダーのサポート:見栄えの良いURLをリライトしたり、古いURLをリダイレクトしたり、静的ページにヘッダーを追加したりできます
- URLのオプションの末尾スラッシュ:末尾のスラッシュの有無を一貫して強制します
- ページバンドルの永続的なキャッシュ:変更されていないページのJavaScriptファイルがビルドをまたいで保持されるようになりました
- 高速リフレッシュの強化:Next.jsのライブ編集エクスペリエンスの信頼性が向上しました
- 本番環境でのReactプロファイリング:プロジェクトのレンダリングの「コスト」を測定するための新しいフラグ
- オプションのキャッチオールルート:動的ルートが、SEO主導のユースケースに対してより柔軟性を提供します
- Webpack 5のサポート(ベータ版):必要に応じて、ビルドサイズと速度が向上したwebpack 5の次のバージョンを選択できます
安定したインクリメンタル静的再生成
Next.jsは9.3で静的サイト生成メソッドを導入しました。明確な目標を持っていました。それは静的な利点(常に高速、常にオンライン、グローバルに複製)を得つつ、Next.jsが得意とする動的なデータに対する優れたサポートも得ることでした。
両方の長所を得るために、Next.jsはインクリメンタル静的生成を導入しました。これにより、サイトのビルド後に静的なコンテンツを更新できます。getStaticPaths
でfallback: true
オプションを使用すると、新しい静的ページを実行時に登録できます。
Next.jsは、データセットのサイズに関係なく、オンデマンドでこの方法で無限の数のページを静的にプリレンダリングできます。
本日、トラフィックが入ってきたときにバックグラウンドで再レンダリングすることにより、既存のページを更新するメカニズムであるインクリメンタル静的再生成の一般提供を発表します。
stale-while-revalidateに触発された、バックグラウンド再生成は、常に静的ストレージから、中断することなくトラフィックが提供されるようにし、新しく構築されたページは、生成が完了した後にのみプッシュされます。
export async function getStaticProps() {
return {
props: await getDataFromCMS(),
// we will attempt to re-generate the page:
// - when a request comes in
// - at most once every second
revalidate: 1,
};
}
revalidateフラグは、https://en.wikipedia.org/wiki/Cache_stampedeを防ぐために、最大1回の生成が行われる秒数です。
従来のSSRとは異なり、インクリメンタル静的再生成を使用すると、静的なメリットを維持できます。
- レイテンシーのスパイクはありません。ページは常に高速に提供されます。
- ページがオフラインになることはありません。バックグラウンドでのページ再生成に失敗した場合、古いページは変更されないままになります。
- データベースとバックエンドの負荷が低い。ページは最大で1回のみ`concurrently`再計算されます。
インクリメンタルな機能(ページの追加と遅延更新)と、プレビューモードの両方が安定し、next start
とVercel Edgeプラットフォームですぐに完全にサポートされるようになりました。
この新機能を実証するために、特定のIssueに対するGitHubの様々なリアクション数を表示する静的ページを再生成する例を作成しました。こちらをご覧ください: https://reactions-demo.vercel.app/


次に、インクリメンタルな静的生成機能に関する2つの追加機能に対応するための補足的なRFCに取り組む予定です。
- 一度に複数のページ(ブログのインデックスや特定のブログ記事など)を再生成および無効化する
- ユーザーのトラフィックに先立ち、イベント(CMSのWebhookなど)をリスニングして再生成する
詳細については、getStaticProps
のドキュメントをご覧ください。
カスタマイズ可能なベースパス
Next.jsプロジェクトは必ずしもドメインのルートから提供されるとは限りません。Next.jsプロジェクトがドメインのそのサブセクションのみをカバーするように、/docs
のようなサブパスの下にNext.jsプロジェクトをホストしたい場合があります。
これまでもこれは可能でしたが、かなりの追加設定が必要でした。例えば、すべての<Link>
にプレフィックスを追加し、Next.jsが正しいパスからJavaScriptバンドルを提供していることを確認する必要がありました。
この問題を解決するために、新しい設定オプションを導入します。basePath
を使用すると、ドメインのサブパスにNext.jsプロジェクトを簡単にホストできます。
basePath
の使用を開始するには、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
にリライトしたい場合があります。
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 [
// check if Next.js project routes match before we attempt proxying
{
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.js
のredirects
キーの下にリダイレクトのリストを作成できるようになりました。
module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
];
},
};
redirects
機能の詳細については、リダイレクトに関するドキュメントをご覧ください。
ヘッダー
Next.jsを使用すると、静的生成とサーバーサイドレンダリングの両方を使用するハイブリッドプロジェクトを構築できます。サーバーサイドレンダリングを使用すると、受信リクエストのヘッダーを設定できます。静的ページの場合、これまでヘッダーを設定することはできませんでした。
next.config.js
に、すべてのNext.jsルートに適用されるheaders
プロパティが導入されました。
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Feature-Policy',
// Disable microphone and geolocation
value: "microphone 'none'; geolocation 'none'",
},
],
},
];
},
};
headers
オプションを使用すると、Feature-Policy
やContent-Security-Policy
のような、一般的に必要なヘッダーを設定できます。
headers
機能の詳細については、ヘッダーに関するドキュメントをご覧ください。
URLの末尾のスラッシュはオプション
Next.jsが3年前に導入されたとき、デフォルトの動作では、末尾にスラッシュが付いたすべてのURLは常に404ページを返していました。
有効ではありましたが、一部のユーザーは、この動作を変更する機能を要求していました。例えば、以前は常に末尾にスラッシュが強制されていた既存のプロジェクトをNext.jsに移行する場合などです。
Next.js 9.5では、next.config.js
にtrailingSlash
という新しいオプションが導入されました。
この新しいオプションにより、Next.jsが末尾のスラッシュの動作を自動的に処理するようになります。
- 例えば、末尾にスラッシュが付いたURLを末尾にスラッシュがないURL(例:
/about/
から/about
)に自動的にリダイレクトします。 trailingSlash
がtrue
に設定されている場合、末尾にスラッシュがないURLは末尾にスラッシュが付いたURL(例:/about
から/about/
)にリダイレクトされます。next/link
に末尾のスラッシュが自動的に適用/削除され、不必要なリダイレクトを回避します。
module.exports = {
// Force a trailing slash, the default value is no trailing slash (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 パターンは次のようになります。
#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 は少し前に、React コンポーネントのパフォーマンスの問題を追跡できるProfiler API を導入しました。この機能は開発では自動的に機能しますが、本番環境でプロファイリングするには、別のバージョンの 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 は現在ベータ版です。これにはいくつかの大きな改善が含まれています。
- Tree-Shaking の改善: ネストされたエクスポート、内部モジュール、および CommonJS がツリーシェイクされます。
- 永続的なキャッシュ: 以前のビルドからの作業の再利用を可能にします。
- 決定論的なチャンク ID とモジュール ID: ビルド間で webpack モジュール ID が変更されるケースを解決します。
本日、Next.js 用の webpack 5 のベータ版が利用可能になったことを発表できることを嬉しく思います。
webpack 5 を試すには、package.json
でYarn resolutionsを使用できます。
{
"resolutions": {
"webpack": "^5.0.0-beta.30"
}
}
Webpack 5 ベータ版はすでに、nextjs.org と vercel.com の本番環境に展開されています。ぜひ段階的に試していただき、GitHub でフィードバックをお寄せください。
コンパイル基盤の改善
webpack 5 をサポートするために、コンパイルパイプラインの多くを Next.js に合わせて書き直しました。
- Next.js は、
webpack-hot-middleware
やwebpack-dev-middleware
に依存せず、webpack を直接使用し、Next.js プロジェクト向けに最適化するようになりました。これにより、アーキテクチャがシンプルになり、開発時のコンパイルが高速化されます。 - オンデマンドエントリ(Next.js が開発中に特定のページにアクセスした際にコンパイルを行うシステム)も書き直され、私たちのユースケースに合わせて調整された新しい webpack の動作を利用することで、さらに信頼性が向上しました。
- React Fast Refresh と Next.js Error Overlay は、webpack 5 と完全に互換性を持つようになりました。
- ディスクキャッシュは、今後のベータ版リリースで有効になります。
後方互換性
私たちは常に、Next.js が以前のバージョンとの後方互換性を確保することに尽力しています。
Webpack 4 は引き続き完全にサポートされます。webpack 4 から 5 への移行が可能な限りスムーズになるよう、webpack チームと緊密に連携しています。
Next.js プロジェクトにカスタム webpack 設定がない場合、webpack 5 を最大限に活用するためにプロジェクトの変更は必要ありません。
重要: プロジェクトにカスタム webpack 設定がある場合は、webpack 5 に移行するためにいくつかの変更が必要になる場合があります。移行手順に注意するか、将来のアップグレードをシームレスにするために、webpack 拡張機能の使用を最小限に抑えることをお勧めします。
macOS でのファイル監視の改善
最近、macOS でコードを数回変更した後、ファイル監視が停止するという webpack の問題を発見しました。更新を確認するには、プロジェクトを手動で再起動する必要がありました。数回変更した後、サイクルが繰り返されました。
さらに、この問題は 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に特別な感謝を申し上げます。
Next.js での webpack 5 サポートを実現する上で協力してくれた webpack の作者であるTobias Koppersに特別な感謝を申し上げます。
このリリースは、@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! の貢献によって実現しました。