2019年7月8日月曜日
Next.js 9
投稿者70回のカナリアリリースを経て、Next.js 9を発表できることを嬉しく思います。主な機能は以下の通りです。
- 組み込みのゼロコンフィグTypeScriptサポート: 自動TypeScriptサポートと統合された型チェックにより、自信を持ってアプリケーションを構築できます。
- ファイルシステムベースの動的ルーティング: カスタムサーバーを必要とせず、ファイルシステムを通じて複雑なアプリケーションルーティング要件を表現できます。
- 自動静的最適化: 機能に妥協することなく、デフォルトでサーバーサイドレンダリングと静的プリレンダリングを活用した超高速ウェブサイトを作成できます。
- APIルート: ホットリロードと統合されたビルドパイプラインを活用し、バックエンドアプリケーションのエンドポイントを迅速に構築できます。
- さらなる本番環境最適化: ビューポート内プリフェッチやその他の最適化により、アプリケーションの応答性がこれまで以上に向上しました。
- DXの改善: 目立たない、使いやすさの改善により、最高の開発ができます。
いつものように、これらの利点がすべて下位互換性を持つよう努めてきました。ほとんどのNext.jsアプリケーションでは、実行するだけで済みます
npm i next@latest react@latest react-dom@latest
コードベースの変更が必要となるケースは非常に稀です。詳細については、アップグレードガイドを参照してください。
前回のリリース以降、IGN、Bang & Olufsen、Intercom、Buffer、そしてFerrariなどの企業がNext.jsでローンチしたことを嬉しく思います。詳細はショーケースをご覧ください!
組み込みのゼロコンフィグTypeScriptサポート
1年前、Next.js 6は、@zeit/next-typescript
というプラグインを通じて基本的なTypeScriptサポートを導入しました。ユーザーはまた、.babelrc
をカスタマイズし、next.config.js
でそれを有効にする必要がありました。
設定すると、このプラグインは.ts
および.tsx
ファイルがNext.jsによってビルドされることを可能にしました。しかし、型チェックは統合されておらず、Next.jsコアから型が提供されることもありませんでした。これは、DefinitelyTypedでコミュニティパッケージを別途メンテナンスする必要があり、リリースと同期が取れない可能性があることを意味しました。
既存および新規の多くのユーザーと話す中で、ほとんどのユーザーがTypeScriptの使用に非常に興味を持っていることが明らかになりました。彼らは、既存または新規のコードベースにTypeScriptを簡単に統合するための、より信頼性が高く標準的なソリューションを求めていました。
そのため、私たちはTypeScriptサポートをNext.jsコアに統合し、開発者エクスペリエンスを向上させ、処理を高速化することに着手しました。
自動セットアップ
Next.jsでTypeScriptを始めるのは簡単です。ファイル、ページ、またはコンポーネントを.js
から.tsx
にリネームします。その後、next dev
を実行するだけです!
これにより、Next.jsはプロジェクトでTypeScriptが使用されていることを検出します。Next.js CLIが、ReactとNode.jsに必要な型をインストールする手順を案内します。
また、Next.jsは、まだ存在しない場合に、適切なデフォルト設定のtsconfig.json
を作成します。このファイルにより、Visual Studio Codeのようなエディタで統合された型チェックが可能になります。
統合された型チェック
Next.jsは、開発時と本番ビルド時の両方で型チェックを処理します。
開発中、Next.jsはファイルを保存した後に型エラーを表示します。型チェックはバックグラウンドで行われるため、ブラウザで更新されたアプリケーションと即座にインタラクトできます。型エラーは利用可能になり次第、ブラウザに伝播されます。
また、型エラーが存在する場合、Next.jsは本番ビルド(next build
)を自動的に失敗させます。これにより、破損したコードが本番環境にデプロイされるのを防ぎます。

TypeScriptで書かれたNext.jsコア
過去数ヶ月で、私たちはコードベースのほとんどをTypeScriptに移行しました。これにより、コード品質が向上しただけでなく、すべてのコアモジュールに型を提供できるようになりました。
たとえば、next/link
をインポートすると、TypeScriptをサポートするエディタは、許可されたプロパティとその値を表示します。

動的ルーティングセグメント
動的ルーティング(URLスラッグまたはPretty/Clean URLとも呼ばれる)は、2.5年前にNext.jsがリリースされて以来、GitHubでの最初の機能リクエストの1つでした!
この問題は、Next.jsをプログラムで利用するためのカスタムサーバーAPIの導入により、Next.js 2.0で「解決」されました。これにより、Next.jsをレンダリングエンジンとして使用し、抽象化と受信URLの特定のページへのマッピングが可能になりました。
私たちはユーザーと話し、多くのアプリケーションを調査した結果、その多くがカスタムサーバーを使用していることを発見しました。あるパターンが浮上しました。カスタムサーバーを使用する最も顕著な理由は、動的ルーティングでした。
しかし、カスタムサーバーには独自の落とし穴があります。ルーティングはプロキシではなくサーバーレベルで処理され、モノリスとしてデプロイおよびスケーリングされ、パフォーマンスの問題が発生しやすいです。
カスタムサーバーはアプリケーション全体を1つのインスタンスで利用可能にする必要があるため、これらの問題を解決するServerless環境にデプロイするのは通常困難です。Serverlessリクエストはプロキシ層でルーティングされ、パフォーマンスのボトルネックを回避するために独立してスケーリング/実行されます。
さらに、私たちはより良い開発者エクスペリエンスを提供できると信じています! Next.jsの魔法の多くは、pages/blog.js
というファイルを作成すると、突然/blog
でページにアクセスできるようになることから始まります。
なぜユーザーは、/blog/my-first-post
(/blog/:id
)のようなルートをサポートするために、独自のサーバーを作成し、Next.jsのプログラムAPIについて学ぶ必要があるのでしょうか?
このフィードバックとビジョンに基づき、私たちはユーザーがすでに知っているpages/
ディレクトリを基盤として、ルートマッピングソリューションの調査を開始しました。
動的にルーティングされたページの作成
Next.jsは、path-to-regexp
(Expressを動かすライブラリ)によって普及したパターンである、基本的な名前付きパラメータを使用したルートの作成をサポートしています。
/post/:pid
ルートに一致するページは、pages
ディレクトリにpages/post/[pid].js
というファイルを作成することで、作成できるようになりました!
Next.jsは、/post/1
、/post/hello-nextjs
などのリクエストを自動的にマッチさせ、pages/post/[pid].js
で定義されたページをレンダリングします。一致するURLセグメントは、[角括弧]
で指定された名前で、クエリパラメータとしてページに渡されます。
例:次のページとリクエスト/post/hello-nextjs
の場合、query
オブジェクトは{ pid: 'hello-nextjs' }
になります。
static async getInitialProps({ query }) {
// pid = 'hello-nextjs'
const { pid } = query
const postContent = await fetch(
`https://api.example.com/post/${encodeURIComponent(pid)}`
).then(r => r.text())
return { postContent }
}
複数の動的URLセグメントもサポートされています!
[param]
構文はディレクトリ名とファイル名でサポートされており、次の例が機能します
./pages/blog/[blogId]/comments/[commentId].js
./pages/posts/[pid]/index.js
この機能の詳細については、Next.jsドキュメントまたはNext.jsラーニングセクションで確認できます。
自動静的最適化
Next.jsは、約2年前にリリースされたv3で静的ウェブサイト生成のサポートを追加しました。当時、これはNext.jsに追加される最も要望の多かった機能でした。
それには正当な理由があります。静的ウェブサイトが高速であることは否定できません! それらはサーバーサイドの計算を必要とせず、CDNロケーションからエンドユーザーに即座にストリーミングできます。
しかし、サーバーサイドレンダリングされたアプリケーションと静的に生成されたアプリケーションの選択は二者択一であり、サーバーサイドレンダリングか静的生成かのどちらかを選択するしかありませんでした。中間はありませんでした。
実際には、アプリケーションには異なる要件がある場合があります。これらの要件には、異なるレンダリング戦略とトレードオフが必要です。
たとえば、ホームページやマーケティングページは通常静的コンテンツを含んでおり、静的最適化の優れた候補です。
一方、製品ダッシュボードは、データが頻繁に更新される場合にサーバーサイドレンダリングから恩恵を受ける可能性があります。
私たちは、ユーザーに両方の良い部分を提供し、デフォルトで高速にする方法を検討し始めました。静的なマーケティングページと動的なサーバーレンダリングページをユーザーにどのように提供できるでしょうか?
Next.js 9から、ユーザーはアプリケーションを完全にサーバーレンダリングするか、静的にエクスポートするかを選択する必要がなくなりました。ページごとに両方の利点を提供します。
自動部分静的エクスポート
ページが静的HTMLにプリレンダリングできるかどうかを自動的に判断するヒューリスティックが導入されました。
この判断は、ページがgetInitialProps
の使用を通じて、ブロッキングデータ要件を持つかどうかによって行われます。
このヒューリスティックにより、Next.jsはサーバーレンダリングされたページと静的に生成されたページの両方を含むハイブリッドアプリケーションを出力できます。
組み込みのNext.jsサーバー(next start
)とプログラムAPI(app.getRequestHandler()
)はどちらもこのビルド出力を透過的にサポートしています。設定や特別な処理は必要ありません。
静的に生成されたページは依然としてリアクティブです。Next.jsは、クライアントサイドでアプリケーションをハイドレートし、完全なインタラクティビティを提供します。
さらに、Next.jsは、ページがURLのクエリパラメータに依存している場合、ハイドレーション後にアプリケーションを更新します。
Next.jsは、開発中にページが静的に生成されるかどうかを視覚的に通知します。この視覚的な表示は、クリックすることで非表示にできます。

静的に生成されたページもNext.jsのビルド出力に表示されます

APIルート
Reactアプリケーションを構築する多くのケースでは、何らかのバックエンドが必要になります。データベースからデータを取得するため、またはユーザーから提供されたデータ(例:お問い合わせフォーム)を処理するためです。
バックエンドを必要とする多くのユーザーがカスタムサーバーを使用してAPIを構築していることがわかりました。その際、彼らはかなりの数の問題に直面しました。たとえば、Next.jsはカスタムサーバーコードをコンパイルしないため、import
/ export
やTypeScriptを使用できませんでした。
このため、多くのユーザーはカスタムサーバーの上に独自のカスタムコンパイルパイプラインを実装することになりました。これは彼らの目標を解決しましたが、多くの落とし穴があります。たとえば、誤って設定すると、アプリケーション全体でツリーシェイキングが無効になる可能性があります。
ここから疑問が生まれました。Next.jsが提供する開発者エクスペリエンスをAPIバックエンドの構築にも持ち込めたらどうだろうか?
本日、Next.jsが提供するバックエンド構築のための最高クラスの開発者エクスペリエンスであるAPIルートを発表できることを嬉しく思います。
APIルートの使用を開始するには、pages/
ディレクトリ内にapi/
というディレクトリを作成します。
このディレクトリ内のすべてのファイルは、他のページファイルがルートにマッピングされるのと同じ方法で、自動的に/api/<your route>
にマッピングされます。
たとえば、pages/api/contact.js
は/api/contact
にマッピングされます。
注: APIルートも動的ルートをサポートしています!
pages/api/
ディレクトリ内のすべてのファイルは、Reactコンポーネントではなく、リクエストハンドラ関数をエクスポートします
export default function handle(req, res) {
res.end('Hello World');
}
req
は、http.IncomingMessageを拡張するNextApiRequestを参照します。res
は、http.ServerResponseを拡張するNextApiResponseを参照します。
一般に、APIエンドポイントは、クエリ文字列、リクエストボディ、クッキーなどの入力データを受け取り、他のデータで応答します。
Next.jsにAPIルートのサポートを追加する調査を行った際、多くの場合、ユーザーがNode.jsのリクエストおよびレスポンスオブジェクトを直接使用していないことに気づきました。代わりに、Expressのようなサーバーライブラリが提供する抽象化を利用していました。
これを行う理由は、多くの場合、受信データは何らかの形式のテキストであり、有用にするためにはまずパースする必要があるためです。したがって、これらの特定のサーバーライブラリは、最も一般的にはミドルウェアを通じて、データを手動でパースする負担を取り除くのに役立ちます。最も一般的に使用されるものはクエリ文字列、ボディ、クッキーのパースを提供しますが、開始するにはまだいくつかの設定が必要です。
Next.jsのAPIルートは、これらのミドルウェアをデフォルトで提供するため、すぐに生産的にAPIエンドポイントを作成できます。
export default function handle(req, res) {
console.log(req.body); // The request body
console.log(req.query); // The url querystring
console.log(req.cookies); // The passed cookies
res.end('Hello World');
}
受信データを使用するだけでなく、APIエンドポイントは通常データを返します。一般的に、この応答はJSONになります。Next.jsは、データを簡単に送信できるように、デフォルトでres.json()
を提供します。
export default function handle(req, res) {
res.json({ title: 'Hello World' });
}
開発中にAPIエンドポイントに変更を加えると、コードが自動的にリロードされるため、サーバーを再起動する必要はありません。
本番環境の最適化
ビューポート内の<Link>
のプリフェッチ
Next.js 9は、<Link>
コンポーネントがビューポートに表示されると自動的にプリフェッチします。
この機能は、新しいページへのナビゲーションをより迅速にすることで、アプリケーションの応答性を向上させます。
Next.jsは、Intersection Observerを使用して、必要なアセットをバックグラウンドでプリフェッチします。
これらのリクエストは優先度が低く、fetch()
またはXHRリクエストに譲ります。ユーザーがデータセーバーを有効にしている場合、Next.jsは自動プリフェッチを回避します。
まれにしか訪問されないページでは、prefetch
プロパティをfalse
に設定することで、この機能を無効にできます。
<Link href="/terms" prefetch={false}>
<a>Terms of Service</a>
</Link>
デフォルトで最適化されたAMP
Next.js 9は、AMP-firstおよびハイブリッドAMPページに対して、デフォルトで最適化されたAMPをレンダリングします。
AMPページはオプトインですが、Next.jsは自動的にその出力を最適化します。これらの最適化により、レンダリング速度が最大50%高速になる可能性があります!
この変更は、Sebastian Benz氏によるAMP Optimizerに関する素晴らしい作業によって実現されました。
typeof window
分岐のデッドコード削除
Next.js 9は、サーバーおよびクライアントのビルド中にtypeof window
を適切な値(undefined
またはobject
)に置き換えます。この変更により、Next.jsは本番ビルドされたアプリケーションからデッドコードを自動的に削除できます。
getInitialProps
またはアプリケーションの他の部分にサーバー専用コードがある場合、ユーザーはクライアントサイドのバンドルサイズが減少することを確認できるはずです。
開発者エクスペリエンスの改善
コンパイルインジケーター
バージョン9より前では、ホットコード置換が行われること(およびNext.jsコンパイラツールチェーンが動作していること)を知る唯一の方法は、開発者コンソールを確認することでした。
しかし、多くの場合、結果のレンダリングを見てしまい、Next.jsがまだコンパイル作業を行っているかどうかを知ることが困難でした。例えば、ページのスタイルに微妙な変更を加えている場合、すぐに更新されたかどうかは分からないかもしれません。
このため、作業が行われていることを示す問題に対する潜在的な解決策を議論するために、RFC / "good first issue"を作成しました。
私たちは、RFCに関して多くのデザイナーやエンジニアからフィードバックを受け取りました。例えば、彼らが何を好み、インジケーターのデザインの潜在的な方向性などです。
Rafael Almeidaは、この機会に私たちのチームと協力し、Next.js 9でデフォルトで利用可能になったまったく新しいインジケーターを実装しました。
Next.jsがコンパイル作業を行っている間は、ページの右下隅に小さな三角形が表示されます!
コンソール出力
従来、開発中に変更を加えると、Next.jsはコンパイル中のインジケーター状態とロード状態のバーの充填を表示し、変更を加えるたびに画面を継続的にクリアしていました。
この動作はいくつかの問題を引き起こします。最も顕著なのは、アプリケーションコードからのコンソール出力がクリアされることです。たとえば、コンポーネントにconsole.log
を追加した場合などです。また、Vercel CLIやdocker-compose
などのログ出力を連結する外部ツールを使用している場合も同様です。
Next.js 9から、ログ出力のジャンプが減り、画面がクリアされなくなりました。これにより、ターミナルウィンドウにより関連性の高い情報が表示され、点滅が少なくなるため、全体的なエクスペリエンスが向上し、Next.jsはすでに使用しているツールとの統合がより良くなります。
出力クリアに協力してくれたJustin Chaseに感謝します。
ビルド出力統計
next build
を使用してアプリケーションを本番用にビルドすると、ビルドされたすべてのページの詳細なビューが表示されるようになりました。
すべてのページは自動的にいくつかの統計情報を受け取ります。
最も顕著なのはバンドルサイズです。アプリケーションが成長するにつれてJavaScriptバンドルも成長します。このビルド時の表示は、本番バンドルの成長を示すのに役立ちます。将来的には、本番ビルドが失敗するページに対してパフォーマンス予算を設定できるようにもなります。

バンドルサイズに加えて、各ページでいくつのプロジェクトコンポーネントとnode_modules
コンポーネントが使用されているかも表示します。これにより、ページの複雑さの指標が得られます。

すべてのページには、静的に最適化されているかサーバーサイドレンダリングされているかの表示もあります。これは、各ページが異なる動作をする可能性があるためです。

ページごとの設定オブジェクト
すべてのページで設定オブジェクトをエクスポートできるようになりました。当初、この設定によりAMPにオプトインできますが、将来的にはより多くのページ固有のオプションを設定できるようになります。
export const config = { amp: true };
export default function AboutPage(props) {
return <h3>My AMP About Page!</h3>;
}
ハイブリッドAMPレンダリングにオプトインするには、'hybrid'
という値を使用できます。
import { useAmp } from 'next/amp';
export const config = { amp: 'hybrid' };
export default function AboutPage(props) {
const isAmp = useAmp();
return <h3>My About Page!{isAmp ? <> Powered by AMP!</> : ''}</h3>;
}
withAmp
高次コンポーネントは、この新しい設定に代わって削除されました。
withAmp
の使用を新しい設定オブジェクトに自動的に変換するコードモッドを提供しています。詳細については、アップグレードガイドを参照してください。
コードベースの改善
最近、私たちはコードベースへの貢献時のエクスペリエンスを向上させ、コードベースの成長に伴う安定性を確保するために、ツールにいくつかの変更を加えました。
TypeScriptのセクションで読んだように、Next.jsコアは現在TypeScriptで書かれており、Next.jsアプリケーションが使用する型が自動的に生成されます。これはNext.jsを使用して構築されたアプリケーションにとって有用であるだけでなく、コアコードベースで作業する際にも役立ちます。型エラーと自動補完が自動的に得られるためです。
Next.jsにはすでに50以上のNext.jsアプリケーションとそれらに対して実行されるテストからなるかなり大規模な統合テストスイートがありました。これらのテストは、新バージョンがリリースされたときに、以前利用可能だった機能が同じテストスイートでテストされるため、スムーズなアップグレードを保証します。
私たちのテストのほとんどは統合テストです。多くの場合、それらは開発中にNext.jsを使用する「実際の」開発者を再現しているためです。例えば、ホットモジュール置換が機能するかどうかを確認するために、Next.jsアプリケーションに変更を加えることを再現するテストがあります。
私たちの統合テストは主にSelenium WebDriverに基づいており、ヘッドレスChromeでのテストにはChromeDriverと組み合わせて使用していました。しかし、時間の経過とともに、他のブラウザ、特にInternet Explorer 11のような古いブラウザで特定の問題が発生するようになりました。
Seleniumを使用していたため、複数のブラウザでテストを自動的に実行できました。
現在、私たちはChrome、Firefox、Safari、およびInternet Explorer 11でテストスイートを実行しています。
Google Chromeとの共同作業
Google Chromeチームは、RFCとプルリクエストを提供することでNext.jsの改善に取り組んでいます。
この共同作業の目標は、バンドルサイズ、起動時間、ハイドレーション時間に焦点を当てた大規模なパフォーマンス向上です。
たとえば、これらの変更は、小規模なウェブサイトだけでなく、Hulu、Twitch、Deliverooのような大規模なアプリケーションのエクスペリエンスも向上させます。
モジュール / ノンモジュール
最初の重点分野は、モダンJavaScriptをサポートするブラウザへのモダンJavaScriptの提供です。
例えば現在、Next.jsは、async
/await
をサポートしないブラウザでコードが実行されると破損してしまうため、その構文に対するポリフィルを提供する必要があります。

古いブラウザが動作しなくなるのを避けつつ、モダンJavaScriptをサポートするブラウザにモダンJavaScriptを送信するために、Next.jsはmodule/nomoduleパターンを利用します。module/nomoduleパターンは、古いブラウザがポリフィルされたES5にフォールバックできるようにしながら、モダンブラウザにモダンJavaScriptを提供する信頼性の高いメカニズムを提供します。
Next.jsにおけるmodule/nomoduleのRFCは、こちらで確認できます。
バンドル分割の改善
Next.jsの現在のバンドル分割戦略は、モジュールを単一の「共通」チャンクに含めるための比率ベースのヒューリスティックに基づいています。バンドルが1つしかないため粒度が非常に低く、コードが不必要にダウンロードされる(共通チャンクが特定のルートで実際には必要ないコードを含む可能性があるため)か、複数のページバンドル間でコードが重複しています。

バンドル分割の改善に関するRFCは、こちらで確認できます。
その他の改善
Chromeチームは、Next.jsを改善する他の多くの最適化や変更にも取り組んでいます。これらのRFCは近日中に共有される予定です。
これらのRFCとプルリクエストは「Collaboration」とラベル付けされており、Next.jsのイシュートラッカーで簡単に見つけることができます。
コミュニティ
Next.jsコミュニティの継続的な成長を大変嬉しく思います。
今回のリリースでは、65人以上のプルリクエスト作成者が主要な改善や例に貢献しました。
例についてですが、Next.jsをさまざまなライブラリやテクノロジーと統合する方法に関する200以上の例を提供しています!これには、ほとんどのcss-in-jsおよびデータフェッチライブラリが含まれます。
- 少なくとも1つのコミットを記録したコントリビューターは**720人**を超えました。
- GitHubでは、プロジェクトは**38,600回**以上スターを獲得しています。
- 最初のリリース以来、**3,400件**を超えるプルリクエストが提出されており、これは前回のメジャーリリース以降で**800件**以上になります!
Next.jsコミュニティは、前回のメジャーリリース以降、メンバー数が**8,600人**を超え、倍増しました。ぜひご参加ください!
今回のリリースを形作る上で貢献してくださったコミュニティの皆様、および外部からのすべてのフィードバックと貢献に感謝いたします。