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

2019年7月8日月曜日

Next.js 9

投稿者

70回のカナリアリリースを経て、Next.js 9をご紹介できることを嬉しく思います。このバージョンには以下の機能が含まれています。

  • 組み込みゼロコンフィグTypeScriptサポート: 自動TypeScriptサポートと統合された型チェックにより、アプリケーションをより自信を持って構築できます。
  • ファイルシステムベースの動的ルーティング: カスタムサーバーを必要とせずに、ファイルシステムを通じて複雑なアプリケーションルーティング要件を表現できます。
  • 自動静的最適化: 機能性を損なうことなく、デフォルトでサーバーサイドレンダリングと静的プリレンダリングを活用する超高速なWebサイトを作成できます。
  • APIルート: ホットリロードと統合されたビルドパイプラインを活用して、バックエンドアプリケーションのエンドポイントを迅速に構築できます。
  • さらに多くの本番環境最適化: ビューポート内でのプリフェッチやその他の最適化により、アプリケーションの応答性がこれまで以上に向上しました。
  • 開発者体験の向上: 邪魔にならず、使いやすい改善により、最高の開発体験を提供します。

いつものように、これらのすべてのメリットが後方互換性を維持するように努めました。ほとんどのNext.jsアプリケーションでは、実行するのは次のコマンドだけです。

ターミナル
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でビルドできました。しかし、型チェックは統合されておらず、Next.jsコアから型も提供されていませんでした。これは、DefinitelyTypedで独立してメンテナンスされるコミュニティパッケージが必要であり、リリースと同期が取れなくなる可能性があったことを意味します。

多くの既存および新規ユーザーと話す中で、ほとんどの人がTypeScriptの使用に非常に興味を持っていることが明らかになりました。彼らは、既存または新規のコードベースにTypeScriptを簡単に統合するための、より信頼性の高い標準的なソリューションを求めていました。

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

自動セットアップ

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 9 自動TypeScriptセットアップ
統合型チェック

Next.jsは、開発中および本番環境のビルドの両方で、型チェックを自動的に処理します。

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

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

Next.jsは、型エラーが存在する場合、本番ビルド(`next build`)も自動的に失敗させます。これにより、壊れたコードを本番環境にデプロイするのを防ぐことができます。

Next.js 9 Production Type-Checking
Next.js 9 本番環境型チェック
Next.jsコアはTypeScriptで記述されています

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

例えば、`next/link`をインポートすると、TypeScriptをサポートするエディタには、許可されるプロパティとその値が表示されます。

Next.js Core Types
Next.js コア型

動的ルーティングセグメント

動的ルーティング(URLスラグまたはPretty/Clean URLsとも呼ばれる)は、Next.jsがリリースされてから2年半、GitHubでの最初の機能リクエストの1つでした!

この問題は、Next.js 2.0でカスタムサーバーAPIを導入して「解決」されました。これにより、Next.jsをプログラムで利用できるようになり、抽象化とURLマッピングが可能になりました。

ユーザーと対話し、多くのアプリケーションを調査した結果、カスタムサーバーを使用しているユーザーが多くいることがわかりました。カスタムサーバーの主な理由として、動的ルーティングが挙げられました。

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

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

さらに、より優れた開発者体験を提供できると考えています!`pages/blog.js`という名前のファイルを作成すると、`/blog`にアクセスできるようになるなど、Next.jsの多くのマジックはここから始まります。

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

このフィードバックとビジョンに基づき、ユーザーがすでに知っている`pages/`ディレクトリを利用したルーティングマッピングソリューションの調査を開始しました。

動的ルーティングされたページの作成

Next.jsは、`path-to-regexp` Expressを支えるライブラリ)で普及したパターンである、基本的な名前付きパラメータを持つルートを作成することをサポートしています。

`pages`ディレクトリに`pages/post/[pid].js`という名前のファイルを作成することで、`/post/:pid`ルートに一致するページを作成できるようになりました!

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で静的Webサイト生成のサポートを追加しました。当時、これはNext.jsに追加される最も要望の多かった機能でした。

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

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

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

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

一方、製品ダッシュボードは、データが頻繁に更新されるサーバーサイドレンダリングから利益を得る可能性があります。

両方の長所を提供し、デフォルトで高速にすることを目指しました。静的なマーケティングページと動的なサーバーレンダリングページをユーザーに提供するにはどうすればよいでしょうか?

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

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

ページを静的HTMLにプリレンダリングできるかどうかを自動的に判断するためのヒューリスティックが導入されました。

この判断は、ページが`getInitialProps` を使用してブロックデータ要件を持っているかどうかによって行われます。

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

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

静的に生成されたページは引き続きリアクティブです。Next.jsは、クライアントサイドでアプリケーションをハイドレーションして、完全なインタラクティビティを提供します。

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

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

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

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

Next.js Build Output Type Indicator
Next.js ビルド出力タイプインジケーター

API Routes

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

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

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

そこで、「Next.jsが提供する開発者体験をAPIバックエンドの構築にもたらしたらどうなるか?」という疑問が浮かびました。

本日、Next.jsのバックエンド構築のためのクラス最高の開発者体験であるAPIルートを紹介します。

APIルートの使用を開始するには、`pages/`ディレクトリ内に`api/`という名前のディレクトリを作成します。

このディレクトリ内のファイルは、他のページファイルがルートにマッピングされるのと同じ方法で、自動的に`/api/`にマッピングされます。

たとえば、`pages/api/contact.js`は`/api/contact`にマッピングされます。

注意: APIルートは動的ルーティングもサポートしています!

`pages/api/`ディレクトリ内のすべてのファイルは、Reactコンポーネントではなく、リクエストハンドラ関数をエクスポートします。

export default function handle(req, res) {
  res.end('Hello World');
}

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

Next.jsにAPIルートサポートを追加する際に調査したところ、多くの場合、ユーザーはNode.jsのリクエストおよびレスポンスオブジェクトを直接使用していませんでした。代わりに、Expressのようなサーバーライブラリによって提供される抽象化を使用していました。

その理由は、多くの場合、受信データは解析される必要がある何らかのテキスト形式であり、これらの特定のサーバーライブラリは、手動でのデータ解析の負担を軽減します。最も一般的に使用されるものは、クエリ文字列、ボディ、Cookieの解析を提供しますが、開始するにはある程度のセットアップが必要です。

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エンドポイントの変更を加えると、コードは自動的にリロードされるため、サーバーを再起動する必要はありません。

本番環境の最適化

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ファーストおよびハイブリッド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 CLIや`docker-compose`のようなログ出力をまとめる外部ツールからのコンソール出力をクリアしてしまいます。

Next.js 9以降、ログ出力のジャンプが減り、画面のクリアがなくなりました。これにより、Next.jsがすでに使用しているツールとより良く統合される一方で、ターミナルウィンドウに、より関連性の高い情報が表示され、ちらつきが少なくなるため、全体的なエクスペリエンスが向上します。

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

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

ビルド出力統計

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

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

最も顕著なのはバンドルサイズです。アプリケーションが成長すると、JavaScriptバンドルも大きくなります。このビルドタイム表示は、本番バンドルの成長を把握するのに役立ちます。将来的には、パフォーマンスバジェットを設定して、ページが本番ビルドに失敗するような設定も可能になる予定です。

Next.js Built Page Size
Next.js ビルド済みページサイズ

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

Next.js Page Package Count
Next.js ページパッケージ数

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

Next.js Built Page Type
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の改善に取り組んでいます。

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

たとえば、これらの変更は小規模なWebサイトの体験を改善しますが、HuluTwitchDeliverooのような大規模アプリケーションの体験も改善します。

モジュール/ノモジュール

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

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

Next.js Module/Nomodule Collaboration RFC
Next.jsのモジュール/ノモジュール連携RFC

古いブラウザの破壊を防ぎつつ、モダンブラウザにモダンJavaScriptを送信するために、Next.jsはモジュール/ノモジュールパターンを利用します。モジュール/ノモジュールパターンは、モダンブラウザにモダンJavaScriptを提供し、古いブラウザがポリフィルされたES5にフォールバックできるようにする信頼性の高いメカニズムを提供します。

Next.jsでのモジュール/ノモジュールのRFCはこちらで見つけることができます。

バンドル分割の改善

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

Next.js Chunking Collaboration RFC
Next.js チャンキング連携RFC

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

その他の改善点

Chromeチームは、Next.jsを改善するための他の多くの最適化と変更も行っています。これらのRFCはまもなく共有されます。

これらのRFCとプルリクエストは、Next.jsの課題追跡で簡単に見つけられるように、「Collaboration」というラベルが付いています。

コミュニティ

Next.jsコミュニティの継続的な成長を見るのが楽しみです。

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

例といえば、さまざまなライブラリやテクノロジーとのNext.jsの統合方法を示す200以上の例を提供しています!ほとんどのcss-in-jsおよびデータ取得ライブラリが含まれています。

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

Next.jsコミュニティは、前回のメジャーリリース以降、8,600人以上のメンバーで倍増しました。参加しましょう!

We are thankful to our community and all the external feedback and contributions that helped shape this release.