2019年9月30日(月)
Next.js 9.0.7
投稿者Next.js 9.0 は約2ヶ月前にリリースされました。それ以来、私たちは7つの小さくても非常に重要なリリースに忙しく取り組んできました。9.0.1、9.0.2、9.0.3、9.0.4、9.0.5、9.0.6、そして9.0.7です。
これらのリリースが、皆様のウェブサイトやアプリケーションにもたらしたものを、破壊的な変更は一切なく、詳しく見ていきましょう。
- Windows環境での並行性の向上:
next build
プロセスがWindowsでより信頼性が高くなり、より効率的に作業を並列化できるようになりました。 - デフォルトでのGzip圧縮:Gzip圧縮がデフォルトで追加され、必要な最適化の手順が削減されました。
- アクティブなページのみでのTypeScriptレポート:組み込みのTypeScriptサポートが、アクティブなページの変更のみを監視するように拡張され、より高速かつ信頼性が高くなりました。
- テレメトリ:Next.jsのどの部分を最適化すべきか、また、最適化が意図した効果をもたらしているかを検証する上で役立ちます。
next/head
要素のトラッキングの改善:next-head
クラスが削除され、実装を検証する特定のツールを実装しやすくなりました。- pagesディレクトリでの非ページの防止:非ページの誤った公開を防ぐことで、アプリケーションのセキュリティと
next build
時間を最適化します。 - ランタイムの改善:
next/dynamic
など、Next.jsの一部の部分が使用されていない場合、ランタイムでは不要になり、バンドルサイズが小さくなります。
Windows環境での並行性の向上
Next.jsは、next build
プロセス中に多くの場所で並行作業を行います。主な用途は、Terserを使用してビルド出力を並列で最小化することです。
以前は、この作業はworker-farm
と呼ばれるパッケージを使用して、多くのCPUにわたって処理されていました。しかし、多くのWindowsユーザーがカスタムwebpack構成で最小化を無効にしていることに気づきました。さらに詳しく調べたところ、worker-farm
はWindowsマシンで一貫して機能しないことがわかりました。
この問題を解決するために、worker-farm
からjest-worker
に移行しました。これにより、macOS、Linux、およびWindowsマシンでのビルドが確実かつ一貫したものになります。
jest-worker
は、その名前が示すように、Jestテストランナーの一部です。Jestがテストケースを並列化するために使用するパッケージです。つまり、このパッケージは非常に実戦的で、信頼性が高く、メンテナンスされています。
jest-worker
は、Node 12の新機能であるworker_threads
もサポートしています。child_process
とは異なり、worker_threads
はメモリを共有できます。つまり、新しいNodeバージョンではビルド時間が短縮されます。
jest-worker
に切り替えることで、Windowsユーザー向けのビルドの並行処理を再度有効にすることができました。
デフォルトでのGzip圧縮
企業がカスタムサーバーを使用する理由を調査していると、ほとんどの場合、圧縮のためであることがわかりました。企業は、HTTP応答のGzip圧縮を処理するcompression
というExpressミドルウェアを追加します。
このミドルウェアは応答を圧縮するため、ユーザーに送信されるバイト数が少なくなります。通常、これはNginxのようなリバースプロキシによって処理される必要があります。リバースプロキシは、シングルスレッドのNodeプロセスからCPU負荷の高い作業を削除します。
しかし、ウェブ上での Next.js の利用状況を調査したところ、多くの企業で圧縮設定がされていないことがわかりました。
Vercelのようなプラットフォームでは、gzip
とbrotli
はプロキシレベルで自動的に処理されます。
セルフホスティングの場合、企業はgzip(compression
またはリバースプロキシ経由)を自分で追加する必要があります。
Next.js 9.0.4以降、next start
またはカスタムのserver.js
を使用する場合、gzip
圧縮がデフォルトで含まれるようになりました。
Node.jsがBrotliをネイティブでサポートするようになったため、brotli
サポートは近日中に提供予定です。
カスタムサーバー経由でアプリケーションで圧縮がすでに有効になっている場合、Next.jsは独自のコンプレッサーを追加しません。
Next.jsは、サーバーレスターゲットを使用する場合、アセットが個別にアップロードされ、Node.jsを介して提供されないため、デフォルトではサーバーレスタゲットの圧縮を含みません。
Vercelなど、圧縮を処理するプラットフォームにデプロイしている場合、変更は必要ありません。
アクティブなページのみのTypeScriptレポート
Next.js 9にはTypeScriptの組み込みサポートが含まれています。必要なのは、単一のページの名前を.js
から.tsx
に変更することだけです。Next.jsは、残りのセットアップを自動的に処理するか、ガイドします。
Next.jsは、開発プロセスと並行してtsc --watch
を実行することにより、型チェックも処理します。開発中、Next.jsにはオンデマンドエントリと呼ばれるコンセプトがあります。この機能は、アクティブに作業しているページのみをコンパイルします。


9.0.4の時点で、Next.jsはオンデマンドエントリによってアクティブにコンパイルされているページに関する型エラーのみをレポートするようになりました。これにより、特定のページセットに焦点を当てながら、多くの型チェックのノイズを減らすことができます。
アプリケーション全体の型チェックは、next build
中に実行されるか、エディターで処理できます。
テレメトリー
Next.jsは3年近く前にリリースされ、この3年間で、新しい機能からすべてのユーザーにとってより良いデフォルトまで、フレームワークは大幅に成長しました。
この改善プロセスへのアプローチは、非常に手動で行われています。
Vercelには、いくつかの大規模なNext.jsアプリケーションがあります。例えば、vercel.com、vercel.com/docs、https://nextjs.dokyumento.jpです。私たちはVercel社内でNext.jsをドッグフーディングしており、その経験に基づいてNext.jsを改善してきました。
さらに、コミュニティと積極的に関わり、フィードバックを集めています。あなたは以前に、あなたの会社でどのようにNext.jsを使用しているかについて、Timと話したことがあるかもしれません。
例えば、カスタムサーバーを使用している場合、カスタムwebpack構成がある場合などです。このフィードバックは、Next.jsの機能開発を推進する上で非常に貴重です。
ただし、このアプローチには問題があり、それは一部のユーザーからしかフィードバックを収集できないということです。このサブセットは、あなた/あなたの会社とは異なるニーズやユースケースを持っている可能性があります。
この例の1つとして、CSSファイルのインポートがあります。これは標準ではありませんが、多くのユーザーがnext-css
(またはSass/Less)またはカスタム構成を使用して、これを使用しているようです。特定のユーザーがどのようなアプローチを使用しているかを把握できれば、改善を優先することができます。
このため、これらのフィードバックポイントを収集するための匿名でより自動化されたアプローチを導入し、近い将来、Next.jsをさらに改善できるようにしました。
これにより、フレームワークに加えられた改善が、すべてのアプリケーションのベースラインを改善しているかどうかを検証することもできます。
テレメトリーの詳細については、nextjs.org/telemetryで詳しく読むことができます。参加したくない場合は、オプトアウトする方法も記載されています。
アクティビティを示すドットによるビルドフィードバック
Next.jsのユーザーと話していると、next build
が何もしていないように見えることがあるという小さなフィードバックがありました。特に視覚的に。
これを解決するために、next build
の実行中にコンソール出力にローディングインジケーターを追加しました。この出力は、コマンドがまだ実行中であり、プロセスがフリーズしていないことを視覚的に示します。
可能な限り、このビルド出力を拡張して、ビルドのより多くの段階を表示する予定です。
next/head
要素の追跡の改善
Next.jsは、アプリケーションのHTMLのレンダリングを担当するため、<head>
要素を管理するための組み込みの方法を提供します。このAPIは、next/head
モジュールを介して公開されます。
例えば、ページにタイトルを追加するには
import Head from 'next/head';
export default function MyPage() {
return (
<>
<Head>
<title>My Title</title>
</Head>
<h1>Hello World</h1>
</>
);
}
HTMLにレンダリングする場合、Next.jsは<Head>
内にレンダリングされたすべてのコンポーネントを収集し、タグをページの<head>
にレンダリングします。
ただし、Next.jsでは、<Link>
コンポーネントを使用してシングルページアプリケーション(SPA)タイプのルート遷移が可能です。
<Link>
をクリックすると、Next.jsはクライアント側でページをレンダリングするために必要なJavaScriptファイルを取得します。次に、ファイルに関連付けられているReactコンポーネントをレンダリングします。
この遷移はクライアント側で発生するため、前のページから挿入された<head>
要素をクリーンアップする必要があります。そうしないと、古い要素が別のページに存在する可能性があります。
以前は、Next.jsはすべての<Head>
が提供する要素にクラス名を追加することで、これらの要素を追跡していました。
上記の例をとると、<head>
は次のようになります。
<head>
<title class="next-head">My Title</title>
</head>
このソリューションは、next/head
を介して挿入されたすべての要素が明確にマークされ、クリーンアップが容易であったため、うまく機能します。
ただし、一部のユーザーから、要素の余分なclass
属性により、外部サービスから追加されたスクリプトが検証されないことがあるという問題が報告されました。
Google ChromeチームのGerald Monacoが、要素にクラス名を必要とせずにクリーンアップ動作を維持する方法を考え出しました。
新しい動作では、Next.jsは、それが(next/head
)レンダリングした要素の数を保持する追加の<meta>
タグを挿入します。これにより、Next.jsはカウントを使用して既存の要素をクリーンアップできます。
その結果、このアプローチにより、複数の要素がページの<head>
に挿入された場合の初期HTMLペイロードサイズが削減されます。
Pagesディレクトリ内の非ページの防止
Next.jsを使い始めるときに最初に行うことは、pages
ディレクトリを作成することです。
規則では、pages
ディレクトリ内のすべてのファイルがアプリケーションのルートになります。簡単な例として、pages/about.js
は/about
になります。
時間が経つにつれて、大小を問わず、ユーザーのアプリケーションのビルドパフォーマンスが低いという報告が時折寄せられるようになりました。
さらに調査を進めた結果、これらのユーザーはコンポーネント構造全体をpages
ディレクトリに作成していたことが判明しました。
pages
ディレクトリ内のすべてのファイルはページとして扱われるため、すべてのコンポーネントがアプリケーション内でページとしてコンパイルされていました。これにより、ビルド時に多くのオーバーヘッドが発生し、無効なページに対して2つ以上のJavaScriptファイルが生成されていました。
さらに、これはNext.jsがコード分割されたチャンクを生成する方法にも部分的に影響を与えていました。これは、Next.jsがページ全体でのライブラリの使用に関するヒューリスティックを使用しているためです。
このため、ユーザーがNext.jsアプリケーションにこの落とし穴を導入しないようにする必要があります。
Next.js 9では、pages
ディレクトリ内のファイルがReactコンポーネントをエクスポートしているかを検証するようになりました。
実際には、これはNext.jsがpages
ディレクトリにページではない可能性があるファイルが見つかったことを警告するメッセージを表示することを意味します。
これにより、ユーザーはページではないファイルを別のディレクトリに移動することが推奨されます。これにより、開発、本番環境、およびコード分割がより高速かつ正確になります。
ランタイムの改善
Next.jsフレームワークは、多くの部分で構成されています。その1つがクライアントサイドのランタイムです。このランタイムは、ハイドレーション、クライアントサイドルーティングなどを処理します。
今回の改善で焦点が当てられたハイドレーションは、サーバーレンダリングまたはプリレンダリングされたHTMLをインタラクティブにするために必要なものです。ハイドレーションは、イベントハンドラーを追加し、useEffect()
やcomponentDidMount
のようなライフサイクルメソッドを呼び出し、アプリケーションをエンドユーザーが使用できる状態にします。
さらに、Next.jsは基本的なハイドレーション以上の処理を行います。たとえば、クライアントサイドのルーターの設定、next/head
の設定、およびnext/dynamic
を介した追加のアプリケーションロジックのロードなどです。
これらの各責任には、独自の特定のランタイム部分もあります。
next/dynamic
の場合、Next.jsは、サーバーでレンダリングされた遅延ロードされたコンポーネントがクライアント側で準備できていることを確認する必要があります。next/dynamic
を使用するたびに、追加のJavaScriptバンドルが生成され、ハイドレーションのミスマッチを避けるために、これらのファイルをハイドレーションの前にロードする必要があります。
以前は、このランタイムは常にNext.jsランタイムバンドルに含まれていました。現在は、アプリケーションでnext/dynamic
を使用する場合にのみ含まれるようになりました。つまり、next/dynamic
を使用しないアプリケーションの場合、ダウンロード、解析、および実行されるJavaScriptが少なくなります。
AppTreeのサポート
Reactエコシステムの一部のライブラリは、非常に特定の方法でサーバーサイドレンダリングを実装しています。特に、ApolloのgetDataFromTree
と呼ばれるサーバーサイドレンダリングソリューションは、Reactツリーをレンダリングし、見つかったすべてのQuery
について結果を待機してから、Reactツリーを再度レンダリングすることで機能します。
デフォルトでは、Next.jsは、useRouter
を使用して読み取ることができるルーターなど、いくつかのコンテキスト値をReactツリーに追加します。
with-apollo
の例でReactツリーをレンダリングする方法は、<App>
をレンダリングし、不足しているプロパティを手動で埋めようとすることでした。Reactコンテキストの追加により、コンテキストプロバイダーは別個の要素であるため、これはもはや不可能になりました。
Next.js 9.0.4以降では、getInitialProps
のコンテキストオブジェクトにAppTree
と呼ばれる新しいプロパティが追加されました。これは、ApolloのgetDataFromTree
のように外部ライブラリがReactツリー全体を走査する必要がある場合のために特別に追加されました。
with-apollo
の例は、変更を反映するように更新されました。すでにアプリケーションにApolloを実装している場合は、AppTree
のアプローチに更新して、useRouter
および将来追加されるその他のAPIがNext.jsアプリケーションで正しく動作するようにすることをお勧めします。
Apolloまたは同様のライブラリを使用していない場合は、AppTreeの使用を避けることをお勧めします。Next.jsチームは、一般的にReactツリーの走査を推奨していないためです。Reactツリーは1回だけでなく複数回レンダリングされるため、パフォーマンスのオーバーヘッドがかなり増加します。
next-server
パッケージの削除
1年以上前に、Next.jsをサーバーレスデプロイ向けに最適化し始めたとき、next-server
というパッケージを作成しました。このパッケージは実験的なものであり、next
パッケージと一緒に公開されました。これは、最小限のNext.jsサーバーランタイムを作成するための実験であり、一般に公開されたドキュメントはありませんでした。
最終的に、このパッケージは成功し、本番サーバーのランタイムが小さくなりました。しかし、Next.jsコンパイラーと静的分析により、ランタイムをさらに小さくする革新的な新しい方法を思いつきました。
これにより、next-server
は廃止され、サーバーレスターゲットに置き換えられました。このターゲットは、next
の代替としてnext-server
パッケージを使用するよりも、はるかに最適化された出力を持ちます。
このパッケージは廃止されており、直接使用することはできませんでしたが、維持されていました。これは、パッケージ間で共有されている内部構造があり、コードを移動するにはかなりの労力がかかるためでした。
最近、この作業を行い、next-server
のコードをnext
パッケージに戻しました。つまり、Next.jsフレームワークのすべてのコードはnext
パッケージに存在することになります。
これにより、初心者も経験豊富な貢献者もNext.jsに貢献しやすくなります。単一のコンパイルプロセスと統合されたビルド構成があります。以前は、next
とnext-server
に個別の設定があり、どのコードが各パッケージに属するかについて恣意的な制約がありました。
Next.jsのアップグレード
プロジェクトが古いバージョンのNext.jsで実行されている場合は、Next.js 9にアップグレードすることをお勧めします。
ほとんどの場合、アップグレードに必要な変更はありません。アップグレードガイドに従って、スムーズなアップグレードを実現してください。
リリース以来、ガイドを更新してくれたすべてのコミュニティ貢献者に感謝いたします。
今後の展望
このブログ記事で概説した新しい最適化は、私たちが取り組んできたより広範な最適化と機能のほんの始まりに過ぎません。
近日中に、進行中のRFCに関する最新情報をお知らせします。それまでは、GitHubのRFCラベルを通じて、ちょっとしたプレビューをご覧いただけます。
これは、私たちが調査してきた機能の一部を示しています。例えば、組み込みCSSサポート、publicディレクトリのサポート、そしてsrcディレクトリのサポートなどがあります。
コミュニティ
Next.jsコミュニティの継続的な成長を嬉しく思っています。
- 少なくとも1つのコミットを完了させたコントリビューターは800人以上です。
- GitHubでは、このプロジェクトは41,100回以上スターされています。
Next.jsコミュニティは前回のメジャーリリースから倍増し、10,900人以上のメンバーがいます。ぜひご参加ください!
コミュニティからの継続的な貢献と、リリースを形作るのに役立つ企業やユーザーからの外部フィードバックに大変感謝しています。