このセクションの内容は、以下のリンクの内容を基に作成されており、CC BY 4.0 ライセンスの対象となります。
特に明記されていない限り、以下の内容は元のコンテンツに基づいて修正および削除された結果であるとみなすことができます。
Rspack はコード分割をサポートしており、コードを他のチャンクに分割できます。生成されるアセットのサイズと数を完全に制御できるため、読み込み時間の向上を実現できます。
ここでは、ブラウザが読み込む必要があるリソースを表す「チャンク」という概念を紹介します。
Rspack は、動的インポートに関する ECMAScript 提案に準拠した import()構文を使用します。
Rspack は require.ensure
をサポートしていません。
index.js
では、import()
を使用して2つのモジュールを動的にインポートすることで、新しいチャンクに分割します。
このプロジェクトをビルドすると、src_bar_js.js
、src_foo_js.js
、main.js
の3つのチャンクが生成されます。これらを確認すると、shared.js
が src_bar_js.js
と src_foo_js.js
の両方に存在することがわかります。重複するモジュールは、後の章で削除します。
shared.js
が2つのチャンクに存在しますが、実行されるのは1回だけです。複数のインスタンスの問題を心配する必要はありません。
これは、コードを分割する最もシンプルで直感的な方法です。ただし、このアプローチでは Rspack を手動で設定する必要があります。複数のエントリポイントから複数のチャンクを分割する方法を見ていきましょう。
これにより、次のビルド結果が得られます。
同様に、これらを調べると、すべてに重複する shared.js
が含まれていることがわかります。
上記で説明したコードセグメンテーションは非常に直感的ですが、最新のブラウザのほとんどは同時ネットワークリクエストをサポートしています。SPA アプリケーションの各ページを単一のチャンクに分割し、ユーザーがページを切り替えるたびに、より大きなチャンクをリクエストする場合、明らかにブラウザの同時ネットワークリクエスト処理能力を有効活用できません。そのため、チャンクをより小さなチャンクに分割できます。このチャンクをリクエストする必要がある場合、これらの小さなチャンクを同時にリクエストするように変更することで、ブラウザのリクエストをより効率的に実行できます。
Rspack はデフォルトで node_modules
ディレクトリ内のファイルと重複するモジュールを分割し、これらのモジュールを元のチャンクから別の新しいチャンクに抽出します。では、なぜ上記の例では shared.js
が複数のチャンクに繰り返し表示されるのでしょうか?これは、私たちの例の shared.js
のサイズが非常に小さいからです。非常に小さなモジュールを個別のチャンクに分割してブラウザに読み込ませると、実際には読み込みプロセスが遅くなる可能性があります。
最小分割サイズを 0 に設定することで、shared.js
を単独で抽出できます。
再ビルドすると、shared.js
が個別に抽出され、shared.js
を含む追加のチャンクが生成物に追加されていることがわかります。
特定のモジュールを強制的に単一のチャンクにグループ化できます。たとえば、次の設定です。
上記の構成により、パスに some-lib
ディレクトリが含まれているすべてのファイルは、lib
という名前の単一のチャンクに抽出できます。some-lib
内のモジュールがほとんど変更されない場合、このチャンクはユーザーのブラウザキャッシュに確実にヒットするため、このようなよく考えられた構成はキャッシュヒット率を高めることができます。
ただし、some-lib
を独立したチャンクに分離することには欠点もあります。チャンクが some-lib
内の非常に小さなファイルのみに依存している場合、some-lib
のすべてのファイルが単一のチャンクに分割されているため、このチャンクは some-lib
チャンク全体に依存する必要があり、ロードボリュームが大きくなります。したがって、cacheGroups.{cacheGroup}.name を使用する場合、慎重な検討が必要です。
cacheGroup の name 設定の効果を示す例を次に示します。
インポートを宣言する際にこれらのインラインディレクティブを使用すると、Rspack はブラウザに次のことを伝える「リソースヒント」を出力します。
例として、HomePage
コンポーネントがあり、LoginButton
コンポーネントをレンダリングし、クリック後にLoginModal
コンポーネントをオンデマンドで読み込むとします。
これにより、<link rel="prefetch" href="login-modal-chunk.js">
がページの head に追加され、ブラウザにアイドル時間に login-modal-chunk.js
ファイルをプリフェッチするように指示します。
親チャンクがロードされると、Rspack はプリフェッチヒントを追加します。
プリロードディレクティブは、プリフェッチと比較して多くの違いがあります。
例として、常に個別のチャンクにある必要がある大きなライブラリに依存する Component
を挙げることができます。
巨大な ChartingLibrary
を必要とする ChartComponent
コンポーネントを考えてみましょう。レンダリング時に LoadingIndicator
を表示し、ChartingLibrary
をオンデマンドでインポートします。
ChartComponent
を使用するページがリクエストされると、<link rel="preload">
を介してcharting-library-chunkもリクエストされます。ページチャンクの方が小さく、より早く完了すると仮定すると、既にリクエストされたcharting-library-chunk
が完了するまで、ページはLoadingIndicator
を表示します。これにより、往復回数が2回から1回になるため、ロード時間のわずかな向上につながります。特にレイテンシの高い環境では効果的です。
webpackPreload
を正しく使用しないと、パフォーマンスが低下する可能性があるため、注意が必要です。
プリロードを独自に制御する必要がある場合があります。例えば、動的インポートのプリロードは非同期スクリプトを介して行うことができます。これは、ストリーミングサーバーサイドレンダリングの場合に役立ちます。
Rspackがスクリプトの読み込みを開始する前にスクリプトの読み込みが失敗した場合(Rspackは、スクリプトがページにない場合、そのコードを読み込むためのスクリプトタグを作成します)、chunkLoadTimeoutが経過するまで、catchハンドラは開始されません。この動作は予期せぬものになる可能性があります。しかし、これは説明可能です。Rspackは、スクリプトが失敗したことを知らないため、エラーをスローできません。Rspackは、エラーが発生した直後に、スクリプトにonerrorハンドラを追加します。
このような問題を防ぐために、エラーが発生した場合にスクリプトを削除する独自のonerrorハンドラを追加できます。
その場合、エラーが発生したスクリプトは削除されます。Rspackは独自のスクリプトを作成し、タイムアウトなしでエラーが処理されます。