コアコンセプト
Turbopack がなぜそんなに高速なのかを理解するために、その内部構造を深く掘り下げてみましょう。
Turbo エンジン
Turbopack が非常に高速なのは、インクリメンタルな計算を可能にする Rust 用の再利用可能なライブラリである Turbo エンジン上に構築されているためです。その仕組みは以下のとおりです。
関数レベルのキャッシング
Turbo エンジンを搭載したプログラムでは、特定の関数を「記憶されるべき」としてマークできます。これらの関数が呼び出されると、Turbo エンジンは**何を引数として呼び出されたか**、そして**何を返したか**を記憶します。そして、それをインメモリキャッシュに保存します。
以下は、バンドラーでこの処理がどのように見えるかの簡単な例です。
まず、2つのファイル api.ts
と sdk.ts
に対して readFile
を呼び出すことから始めます。次に、これらのファイルを bundle
し、それらを concat
で結合し、最後に fullBundle
を得ます。これらの関数呼び出しの結果はすべて、後で使用するためにキャッシュに保存されます。
開発サーバーで実行しているとします。あなたは自分のマシンで sdk.ts
ファイルを保存します。Turbopack はファイルシステムイベントを受信し、readFile("sdk.ts")
を再計算する必要があることを認識します。
sdk.ts
の結果が変更されたため、再度 bundle
し、次に再度連結する必要があります。
重要なのは、api.ts
は変更されていないということです。その結果をキャッシュから読み取り、代わりにそれを concat
に渡します。そのため、読み取って再度バンドルする手間を省き、時間を節約できます。
これを、読み取るファイルが数千、実行する変換が多数ある実際のバンドラーで想像してみてください。考え方は同じです。関数呼び出しの結果を記憶し、以前に実行した作業を再度実行しないことで、莫大な量の作業を節約できます。
キャッシュ
Turbo エンジンは現在、キャッシュをメモリに保存しています。つまり、キャッシュは実行中のプロセスが終了するまで存続します。これは開発サーバーに最適です。Next.js 13 以降で next dev --turbo
を実行すると、Turbo エンジンでキャッシュが開始されます。開発サーバーをキャンセルすると、キャッシュはクリアされます。
将来的には、このキャッシュを永続化する予定です。ファイルシステムに保存するか、Turborepo のようなリモートキャッシュに保存するかのいずれかです。これにより、Turbopack は**実行やマシンを超えて**実行された作業を記憶できるようになります。
どのように役立つのか?
このアプローチにより、Turbopack はアプリケーションへのインクリメンタルな更新を計算する際に非常に高速になります。これにより、Turbopack は開発中の更新処理に最適化され、開発サーバーは常に変更に迅速に応答します。
将来的には、永続的なキャッシュにより、プロダクションビルドがはるかに高速になる可能性があります。**実行を超えて**実行された作業を記憶することで、新しいプロダクションビルドは変更されたファイルのみを再構築でき、時間の大幅な節約につながる可能性があります。
リクエストによるコンパイル
Turbo エンジンは、開発サーバーでの非常に高速な*更新*を支援しますが、もう 1 つ重要な指標として、起動時間があります。開発サーバーの起動が速ければ速いほど、作業に取りかかるのが早くなります。
プロセスを高速化するには、より速く作業するか、作業量を減らすかの 2 つの方法があります。開発サーバーを起動する場合、作業量を減らす方法は、起動に必要な*コードのみを*コンパイルすることです。
ページレベルのコンパイル
2〜3 年前の Next.js のバージョンでは、開発サーバーを表示する前に*アプリケーション全体*をコンパイルしていました。Next.js 11 (新しいタブで開きます)では、*リクエストしたページのコードのみ*をコンパイルし始めました。
それは改善されましたが、完璧ではありません。 /users
に移動すると、すべてのクライアントおよびサーバーモジュール、動的インポートされたモジュール、および参照されている CSS と画像がバンドルされます。つまり、ページのかなりの部分が表示されていない場合や、タブの後ろに隠れている場合でも、結局はコンパイルしてしまうことになります。
リクエストレベルコンパイル
Turbopack は、リクエストされたコードのみをコンパイルするほど賢いです。つまり、ブラウザが HTML をリクエストした場合、HTML のみコンパイルし、HTML が参照するものはコンパイルしません。
ブラウザが CSS を要求した場合、その CSS のみをコンパイルし、参照されている画像はコンパイルしません。next/dynamic
の背後にある大規模なグラフライブラリがありますか?グラフを表示するタブが表示されるまでコンパイルしません。 Turbopack は、Chrome DevTools が開いていない限り、ソースマップをコンパイルしないことさえ知っています。
ネイティブ ESM を使用した場合、同様の動作が得られるでしょう。ただし、ネイティブ ESM は、サーバーへのリクエストを大量に生成します。「Turbopack を選ぶ理由」セクションで説明したように。リクエストレベルコンパイルを使用すると、リクエスト数を減らすと同時に、ネイティブの速度でコンパイルできます。「ベンチマーク」で確認できるように、これはパフォーマンスを大幅に向上させます。