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

2019年7月8日月曜日

Next.js 9

投稿者
Connor Davis
Connor Davis@connordav_is
... (以下、投稿者情報は省略。日本語で名前とTwitter IDを併記する形にしても良い)

70回のカナリアリリースを経て、Next.js 9をリリースしました。主な機能は以下のとおりです。

  • ビルトインゼロコンフィグTypeScriptサポート: 自動TypeScriptサポートと統合型チェックにより、アプリケーションをより確実に構築できます。.
  • ファイルシステムベースの動的ルーティング: カスタムサーバーを必要とせずに、ファイルシステムを介して複雑なアプリケーションルーティング要件を表現できます。
  • 自動静的最適化: 機能を損なうことなく、デフォルトで_サーバーサイドレンダリングと静的プリレンダリング_を活用した超高速Webサイトを作成できます。
  • APIルート: ホットリローディングと統合ビルドパイプラインを活用して、バックエンドアプリケーションエンドポイントを迅速に構築できます。
  • さらなる本番環境の最適化: ビューポートプリフェッチングなどの最適化により、アプリケーションの応答性がこれまで以上に高まりました。
  • 改善されたDX: 最適な開発を支援するための、控えめで使いやすい改善。

これまでと同様に、これらのすべてのメリットが下位互換性を持つように努めてきました。ほとんどのNext.jsアプリケーションでは、以下を実行するだけで済みます。

ターミナル
npm i next@latest react@latest react-dom@latest

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

前回のリリース以降、IGN...(以下略、企業名と外部リンクはそのまま)などの企業がNext.jsでローンチしたことを嬉しく思います。詳しくはショーケース...をご覧ください!

ビルトインゼロコンフィグTypeScriptサポート...

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

構成すると、プラグインにより、Next.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に必要なタイプをインストールする手順を案内します。

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 本番時型チェック
TypeScript で書かれた Next.js コア

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

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

Next.js Core Types
Next.js コア型

動的ルートセグメント

動的ルーティング (URLスラッグまたはプリティ/クリーンURLとも呼ばれます) は、Next.js が2.5年前にリリースされた後、GitHub で最初に要求された機能の1つでした。

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

私たちはユーザーと話し、彼らのアプリケーションの多くを調べ、その多くがカスタムサーバーを持っていることを発見しました。パターンが現れました。カスタムサーバーの最も顕著な理由は動的ルーティングでした。

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

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

さらに、私たちはより良い開発エクスペリエンスを提供できると信じています。Next.js の魔法の多くは、pages/blog.js という名前のファイルを作成すると、突然 /blog でアクセスできるページが作成されるときに始まります。

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

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

動的にルーティングされたページの作成 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 学習セクション を参照してください。

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

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

この決定は、getInitialProps を使用して、ページにブロッキングデータ要件があるかどうかによって行われます。

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

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

静的に生成されたページは依然として反応性があります。Next.js は、アプリケーションをクライアント側でハイドレートして、完全なインタラクティブ性を提供します。

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

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

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

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

Next.js Build Output Type Indicator
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エンドポイントは、クエリ文字列、リクエストボディ、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 CLIdocker-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 の使用を新しい設定オブジェクトに自動的に変換する codemod を提供しています。アップグレードガイド で詳細を読むことができます。

コードベースの改善

コードベースに貢献する際のエクスペリエンスを向上させ、コードベースの成長に伴う安定性を確保するために、最近ツーリングにいくつかの変更を加えました。

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 のような大規模なアプリケーションのエクスペリエンスも向上させます。

モジュール / Nomodule

最初の焦点は、最新の JavaScript をサポートするブラウザに最新の JavaScript を提供することです。

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

Next.js Module/Nomodule Collaboration 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 Chunking Collaboration RFC
Next.jsチャンキングコラボレーションRFC

バンドル分割の改善に関するRFCはこちらにあります。

その他の改善

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

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

コミュニティ

Next.jsコミュニティの継続的な成長を嬉しく思います。

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

例について言えば、Next.jsをさまざまなライブラリやテクノロジーと統合する方法について、200以上の例を提供しています。 ほとんどのcss-in-jsとデータフェッチライブラリが含まれています。

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

Next.jsコミュニティは前回のメジャーリリース以降、**8,600人以上のメンバー**で2倍になりました。 ご参加ください!

このリリースの形成に役立ったコミュニティとすべての外部からのフィードバックと貢献に感謝します.