依存関係の事前バンドル
初めて、vite
を実行すると、Vite は、あなたのサイトをローカルで読み込む前に、プロジェクトの依存関係を事前バンドルします。これはデフォルトで自動的に、かつ透過的に行われます。
その理由は?
これは、Vite が「依存関係の事前バンドル」を実行しています。
このプロセスには 2 つの目的があります:
- CommonJS と UMD の互換性: 開発中の Vite のコードは ECMAScript モジュールとして提供しています。そのため、Vite は、CommonJS または、UMD を ESM に変換する必要があります。CommonJS の依存関係を変換する場合、Vite はインポート文をスマート分析を実行してエクスポートが動的に割り当てられていても、CommonJS モジュールは期待通りに動作します。(例 React):
// works as expected
import React, { useState } from 'react'
- パフォーマンス: Vite は、多くの内部モジュールを持つ ESM の依存関係を単一のモジュールに変換して、その後のページロードのパフォーマンスを向上させます。いくつかのパッケージでは、ECMAScript モジュールのビルドを、相互にインポートする別々のファイルとして出力します。
一例として lodash-es
には、600 以上の内部モジュールがあります。import { debounce } from 'lodash-es'
をすると、ブラウザーは 600 以上の HTTP リクエストを同時に処理します! サーバー側では問題なく処理していても、大量のリクエストによりブラウザー側でネットワークの混雑が発生し、ページの読み込みが著しく遅くなってしまいます。
事前に lodash-es
を単一のモジュールにバンドルすることにより HTTP リクエストは 1 つだけで済むようになりました。
注意
依存関係の事前バンドルは開発モードでのみ適用され、依存関係を ESM に変換するために esbuild
を使用します。本番ビルドでは、代わりに @rollup/plugin-commonjs
が使用されます。
依存関係の自動検出
既存のキャッシュが見つからない場合、Vite はソースコードをクロールし、依存関係のインポート(すなわち、node_modules
から解決されることを期待されている "bare imports")を自動的に検出します。そして、検出されたインポートを事前バンドルのエントリーポイントとして使用します。事前バンドルは esbuild
で実行されるので、例のごとく非常に高速です。
サーバーを起動したあと、キャッシュにない新しい依存関係のインポートに遭遇した場合は、Vite は依存関係の事前バンドルを再実行し、必要に応じてページをリロードします。
モノレポとリンクされた依存関係
モノレポの設定では、依存関係は同じリポジトリーからのリンクされたパッケージの可能性があります。Vite は node_modules
から解決されない依存関係を自動的に検出し、リンクされた依存関係をソースコードとして扱います。リンクされた依存関係をバンドルしようとはせず、代わりにリンクされた依存関係のリストを分析します。
ただしこの場合、リンクされた依存関係が ESM としてエクスポートされている必要があります。そうでない場合は、optimizeDeps.include
と build.commonjsOptions.include
に依存関係を追加して、設定することができます。
export default defineConfig({
optimizeDeps: {
include: ['linked-dep'],
},
build: {
commonjsOptions: {
include: [/linked-dep/, /node_modules/],
},
},
})
リンクされた依存関係を変更する場合は、--force
コマンドラインオプションを指定して開発サーバーを再起動すると、変更が有効になります。
挙動のカスタマイズ
デフォルトのヒューリスティックな方法による依存関係の発見によって、必ずしも望ましい結果が得られるとは限りません。リストから依存関係を明示的に含めたり除外したりする場合は、optimizeDeps
設定オプションを使用してください。
optimizeDeps.include
または optimizeDeps.exclude
の一般的な使用例は、ソースコードで直接検出できないインポートがある場合です。たとえば、インポートはプラグイン変換の結果として作成される可能性があります。これは、Vite が最初のスキャンでインポートを検出できないことを意味します。つまり、ファイルがブラウザーによって要求されて変換された後にのみ、インポートを検出できます。 これにより、サーバーの起動後すぐにサーバーが再バンドルされます。
これには、include
と exclude
の両方が使用できます。依存関係が大きい(多くの内部モジュールがある)場合や、CommonJS の場合には、それを含める必要があります。依存関係が小さく、すでに有効な ESM の場合には、それを除外し、ブラウザーに直接読み込ませることができます。
esbuild も optimizeDeps.esbuildOptions
オプションでさらにカスタマイズできます。例えば、esbuild のプラグインを追加して、依存関係にある特殊なファイルを扱えるようにするか、build target
を変更します。
キャッシュ
File System キャッシュ
Vite は、node_modules/.vite
に、事前バンドル済みの依存関係をキャッシュします。いくつかのソースに基づいて、事前バンドルを再実行する必要があるかどうか決定します:
- パッケージマネージャーのロックファイルの内容、例:
package-lock.json
、yarn.lock
、pnpm-lock.yaml
、bun.lockb
など。 - もし存在すれば、vite.config.js の関連するフィールド。
- パッチフォルダーの変更時間。
NODE_ENV
の値。
上記のいずれかが変更された場合のみ、事前バンドルを再実行する必要があります。
何らかの理由で Vite に再バンドルを強制したい場合は、開発サーバーを --force
コマンドラインオプションで起動するか、手動で node_modules/.vite
のキャッシュディレクトリーを削除します。
ブラウザーキャッシュ
解決された依存関係のリクエストは、開発中のページの再読み込みのパフォーマンスを向上させるために、HTTP ヘッダー max-age = 31536000、immutable
で積極的にキャッシュされます。一度キャッシュされると、これらのリクエストは開発サーバーに再び到達することはありません。異なるバージョンがインストールされた(パッケージマネージャーのロックファイルに反映された)場合は、付与されているバージョンクエリーによって自動的に無効になります。ローカルでの編集で依存関係をデバッグしたい場合は、以下のように行えます:
- ブラウザーの devtools のネットワークタブからキャッシュを一時的に無効にします。
- Vite 開発サーバーを
--force
フラグで再起動して、依存関係を再バンドルします。 - ページをリロードします。