Backブログに戻る

Next.js 9

Next.js 9 では TypeScript サポート、ダイナミックルーティング、API ルート、自動静的最適化などが導入されました!

70回のカナリアリリースを経て、Next.js 9の登場をお知らせします。主な新機能は以下の通りです:

これまで通り、これらの利点が後方互換性を保つよう努めました。ほとんどのNext.jsアプリケーションでは、以下のコマンドを実行するだけでアップグレード可能です:

Terminal
npm i next@latest react@latest react-dom@latest

コードベースの変更が必要なケースは非常に稀です。詳細はアップグレードガイドをご覧ください。

前回のリリース以降、IGNBang & OlufsenIntercomBufferFerrariなどの企業がNext.jsを採用しています。詳細はショーケースをご覧ください!

ゼロコンフィグのTypeScriptサポート

1年前のNext.js 6では、@zeit/next-typescriptプラグインを通じて基本的なTypeScriptサポートが導入されました。ユーザーは.babelrcのカスタマイズとnext.config.jsでの有効化が必要でした。

設定後、プラグインは.ts.tsxファイルのビルドを許可しましたが、型チェックの統合やNext.jsコアからの型提供はありませんでした。このため、リリースと同期しない可能性のあるコミュニティパッケージをDefinitelyTypedで別途管理する必要がありました。

多くの新規・既存ユーザーと話す中で、TypeScriptの利用に強い関心があることが明らかになりました。既存または新規コードベースへのTypeScript統合のため、より信頼性が高く標準的なソリューションを求めていました。

このため、TypeScriptサポートをNext.jsコアに統合し、開発者体験を向上させつつ、プロセスを高速化することにしました。

自動セットアップ

Next.jsでTypeScriptを始めるのは簡単:任意のファイル、ページ、コンポーネントを.jsから.tsxにリネームし、next devを実行するだけです。

これによりNext.jsはプロジェクトでTypeScriptが使用されていることを検出します。Next.js CLIがReactとNode.jsに必要な型のインストールをガイドします。

tsconfig.jsonが存在しない場合、Next.jsは適切なデフォルト値でこのファイルを作成します。このファイルによりVisual Studio Codeなどのエディタで統合型チェックが可能になります。

Next.js 9 自動TypeScriptセットアップ

統合型チェック

Next.jsは開発時とプロダクションビルド時の型チェックを処理します。

開発中、Next.jsはファイル保存後の型エラーを表示します。型チェックはバックグラウンドで実行されるため、更新されたアプリケーションをブラウザで即座に操作可能です。型エラーは利用可能になるとブラウザに伝播します。

Next.js 9 開発時型チェック

Next.jsは型エラーがある場合、プロダクションビルド(next build)を自動的に失敗させます。これにより壊れたコードのプロダクションへのデプロイを防ぎます。

Next.js 9 プロダクション型チェック

Next.js 9 プロダクション型チェック

TypeScriptで書かれたNext.jsコア

過去数ヶ月でコードベースの大部分をTypeScriptに移行しました。これによりコード品質が強化されただけでなく、すべてのコアモジュールに型を提供できるようになりました。

例えば、next/linkをインポートすると、TypeScriptをサポートするエディタが許可されたプロパティと受け入れ可能な値を表示します。

Next.js コア型

Next.js コア型

ダイナミックルートセグメント

ダイナミックルーティング(URLスラッグまたはクリーンURLとも呼ばれる)は、Next.jsが2.5年前にリリースされて以来、GitHubで最初に要望の多かった機能の一つでした!

この問題はNext.js 2.0でプログラム的なNext.js使用のためのカスタムサーバーAPIを導入することで「解決」されました。これによりNext.jsをレンダリングエンジンとして使用し、抽象化と特定ページレンダリングのための受信URLマッピングが可能になりました。

ユーザーと話し、多くのアプリケーションを調査した結果、カスタムサーバーを使用しているケースが多いことが分かりました。パターンが明らかになりました:カスタムサーバーを使用する最も顕著な理由はダイナミックルーティングでした。

しかし、カスタムサーバーには独自の落とし穴があります:ルーティングがプロキシレベルではなくサーバーレベルで処理され、モノリスとしてデプロイ/スケーリングされ、パフォーマンス問題が発生しやすくなります。

カスタムサーバーはアプリケーション全体を1つのインスタンスで利用可能にする必要があるため、これらの問題を解決するサーバーレス環境へのデプロイが通常困難です。サーバーレスリクエストはプロキシ層でルーティングされ、パフォーマンスボトルネックを避けるために独立してスケーリング/実行されます。

さらに、私たちはより優れた開発者体験を提供できると考えています!Next.jsの魔法の多くは、pages/blog.jsという名前のファイルを作成すると突然/blogでアクセス可能なページができることから始まります。

ユーザーが/blog/my-first-post/blog/:id)のようなルートをサポートするために、独自のサーバーを作成しNext.jsのプログラムAPIについて学ぶ必要があるでしょうか?

このフィードバックとビジョンに基づき、ユーザーが既に知っているもの(pages/ディレクトリ)によって駆動されるルートマッピングソリューションの調査を開始しました。

ダイナミックルートページの作成

Next.jsはpath-to-regexpExpressを支えるライブラリ)で普及した基本的な名前付きパラメータパターンによるルート作成をサポートします。

/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 Learnセクションでご覧いただけます。

自動静的最適化

Next.jsは約2年前にリリースされたv3で静的ウェブサイト生成のサポートを追加しました。当時、これはNext.jsに追加される最も要望の多かった機能でした。

そして良い理由があります:静的ウェブサイトが_高速_であることは否定できません!サーバーサイドの計算を必要とせず、CDNロケーションからエンドユーザーに即座にストリーミングできます。

しかし、サーバーサイドレンダリングと静的生成のアプリケーションの選択は二者択一でした。サーバーサイドレンダリングか静的生成のどちらかを選ぶ必要がありました。中間の選択肢はありませんでした。

実際には、アプリケーションには異なる要件があります。これらの要件には異なるレンダリング戦略とトレードオフが必要です。

例えば、ホームページやマーケティングページには通常静的コンテンツが含まれており、静的最適化の優れた候補です。

一方、製品ダッシュボードはデータが頻繁に更新されるため、サーバーサイドレンダリングの恩恵を受ける可能性があります。

私たちは、ユーザーに両方の世界のベストを提供し、デフォルトで高速にする方法を探り始めました。静的マーケティングページと動的サーバーレンダリングページをユーザーに提供するにはどうすればよいでしょうか?

Next.js 9から、ユーザーはアプリケーションを完全にサーバーレンダリングするか静的にエクスポートするかの選択をする必要がなくなりました。ページごとに両方の世界のベストを提供します。

自動部分静的エクスポート

ページがgetInitialPropsを使用してブロッキングデータ要件を持つかどうかによって、ページを静的HTMLにプリレンダリングできるかどうかを自動的に決定するヒューリスティックが導入されました。

このヒューリスティックにより、Next.jsはサーバーレンダリングと静的生成ページの両方を含むハイブリッドアプリケーションを出力できます。

組み込みのNext.jsサーバー(next start)とプログラムAPI(app.getRequestHandler())はどちらもこのビルド出力を透過的にサポートします。設定や特別な処理は必要ありません。

静的に生成されたページもまだ反応的です:Next.jsはクライアントサイドでアプリケーションをハイドレートし、完全なインタラクティブ性を与えます。

さらに、Next.jsはページがURLのクエリパラメータに依存している場合、ハイドレーション後にアプリケーションを更新します。

Next.jsは開発中、ページが静的に生成される場合に視覚的に通知します。この視覚的アーティファクトはクリックすることで非表示にできます。

Next.js 静的最適化インジケーター

Next.js 静的最適化インジケーター

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

Next.js ビルド出力タイプインジケーター

Next.js ビルド出力タイプインジケーター

APIルート

Reactアプリケーションを構築する多くの場合、何らかのバックエンドが必要になります。データベースからデータを取得するため、またはユーザーが提供したデータ(例:コンタクトフォーム)を処理するためです。

バックエンドが必要な多くのユーザーがカスタムサーバーを使用してAPIを構築していることがわかりました。これにより、いくつかの問題が発生しました。例えば、Next.jsはカスタムサーバーコードをコンパイルしないため、import/exportやTypeScriptを使用できませんでした。

このため、多くのユーザーはカスタムサーバーの上に独自のカスタムコンパイルパイプラインを実装することになりました。これで目標は達成されましたが、多くの落とし穴があります:例えば、設定が間違っているとアプリケーション全体のツリーシェイキングが無効になる可能性があります。

この問題から、Next.jsが提供する開発者体験をAPIバックエンドの構築にもたらすことはできないかという疑問が生まれました。

今日、APIルートの導入を発表できることを嬉しく思います。Next.jsの一流の開発者体験をバックエンド構築にもたらします。

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

一般的にAPIエンドポイントはクエリ文字列、リクエストボディ、クッキーなどの受信データを受け取り、他のデータで応答します。

Next.jsにAPIルートサポートを追加する調査中に、多くの場合ユーザーがNode.jsのリクエストとレスポンスオブジェクトを直接使用していないことがわかりました。代わりに、Expressなどのサーバーライブラリが提供する抽象化を使用していました。

これを行う理由は、多くの場合受信データが有用になる前に解析が必要な何らかの形式のテキストであるためです。したがって、これらの特定のサーバライブラリは、一般的にミドルウェアを通じてデータを手動で解析する負担を軽減します。最も一般的に使用されるものはクエリ文字列、ボディ、クッキーの解析を提供しますが、それでも開始するにはいくつかの設定が必要です。

Next.jsのAPIルートはこれらのミドルウェアをデフォルトで提供するため、APIエンドポイントをすぐに作成して生産性を発揮できます:

export default function handle(req, res) {
  console.log(req.body); // リクエストボディ
  console.log(req.query); // URLクエリ文字列
  console.log(req.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>利用規約</a>
</Link>

デフォルトで最適化されたAMP

Next.js 9では、AMPファーストおよびハイブリッド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コンパイルインジケーター

コンソール出力

従来、開発中に変更を加えると、Next.jsはコンパイルインジケーターの状態を表示し、ローディング状態のバーが埋まり、変更を加えるたびに画面がクリアされ続けていました。

この動作にはいくつかの問題がありました。最も顕著なのは、コンポーネントにconsole.logを追加した場合など、アプリケーションコードからのコンソール出力がクリアされることです。また、Vercel CLIdocker-composeのようなログ出力を結合する外部ツールを使用している場合にも影響がありました。

Next.js 9から、ログ出力のジャンプが減り、画面がクリアされなくなりました。これにより、ターミナルウィンドウにより関連性の高い情報が表示され、フリッカーが減るため、全体的に優れた体験が得られます。また、Next.jsは既に使用しているツールとより良く統合されます。

Next.js開発コンソール出力

出力クリアに関する協力に感謝するJustin Chaseに特に感謝します。

ビルド出力統計

next buildを使用してアプリケーションを本番用にビルドすると、ビルドされたすべてのページの詳細なビューが表示されるようになりました。

各ページにはいくつかの統計が自動的に表示されます。

最も目立つのはバンドルサイズです。アプリケーションが成長するにつれてJavaScriptバンドルも大きくなりますが、このビルド時の表示により、本番バンドルの成長を把握できます。将来的には、ページに対してパフォーマンス予算を設定し、本番ビルドを失敗させることも可能になります。

Next.jsビルドページサイズ

Next.jsビルドページサイズ

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

Next.jsページパッケージ数

Next.jsページパッケージ数

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

Next.jsビルドページタイプ

Next.jsビルドページタイプ

ページごとの設定オブジェクト

各ページで設定オブジェクトをエクスポートできるようになりました。最初はこの設定でAMPをオプトインできますが、将来的にはより多くのページ固有のオプションを設定できるようになります。

pages/about.js
export const config = { amp: true };
 
export default function AboutPage(props) {
  return <h3>My AMP About Page!</h3>;
}

ハイブリッドAMPレンダリングをオプトインするには、値'hybrid'を使用します:

pages/about.js
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を改善する作業を行っています。

この協力の目的は、バンドルサイズ、起動時間、ハイドレーション時間に焦点を当てた大規模なパフォーマンス改善です。

例えば、これらの変更は小規模なウェブサイトの体験を改善するだけでなく、HuluTwitchDeliverooのような大規模なアプリケーションの体験も改善します。

Module / Nomodule

最初の焦点領域は、モダンなJavaScriptをサポートするブラウザにモダンなJavaScriptを配信することです。

例えば現在、Next.jsはasync/await構文のポリフィルを提供する必要があります。コードがasync/awaitをサポートしていないブラウザで実行される可能性があり、これが壊れるためです。

Next.js Module/Nomodule協力RFC

Next.js Module/Nomodule協力RFC

古いブラウザを壊さずに、モダンなJavaScriptをサポートするブラウザに送信するために、Next.jsはmodule/nomoduleパターンを利用します。module/nomoduleパターンは、モダンなブラウザにモダンなJavaScriptを提供する信頼性の高いメカニズムを提供し、古いブラウザはポリフィルされたES5にフォールバックできます。

Next.jsでのmodule/nomoduleのRFCはこちらで見つけることができます。

改善されたバンドル分割

Next.jsの現在のバンドル分割戦略は、単一の「commons」チャンクにモジュールを含めるための比率ベースのヒューリスティックに基づいています。1つのバンドルしかないため、非常に粒度が低く、特定のルートに実際には必要のないコードがダウンロードされる(commonsチャンクに含まれる可能性があるため)か、コードが複数のページバンドルで重複しています。

Next.jsチャンキング協力RFC

Next.jsチャンキング協力RFC

改善されたバンドル分割のRFCはこちらで見つけることができます。

その他の改善

Chromeチームは、Next.jsを改善する多くの他の最適化や変更にも取り組んでいます。これらのRFCはすぐに共有される予定です。

これらのRFCとプルリクエストには「Collaboration」ラベルが付けられているため、Next.jsのイシュートラッカーで簡単に見つけることができます。

コミュニティ

Next.jsコミュニティの継続的な成長を見るのは嬉しいことです。

このリリースでは、65人以上のプルリクエスト作成者がコアの改善や例を提供しました。

例について言えば、Next.jsをさまざまなライブラリや技術と統合する方法の200以上の例を提供しています!ほとんどのCSS-in-JSやデータフェッチングライブラリを含みます。

  • 720人以上の貢献者が少なくとも1つのコミットをしています。
  • GitHubでは、プロジェクトは38,600回以上スターされています。
  • 最初のリリース以来、3,400以上のプルリクエストが提出され、前回のメジャーリリース以来800以上増加しました!

Next.jsコミュニティは前回のメジャーリリース以来2倍になり、8,600人以上のメンバーがいます。参加しましょう!

私たちはコミュニティと、このリリースを形作るのに役立ったすべての外部のフィードバックと貢献に感謝しています。