Skip to content

May 9th, 2024

Vite Meetup SF

依存関係の事前バンドル

初めて、vite を実行すると、Vite は、あなたのサイトをローカルで読み込む前に、プロジェクトの依存関係を事前バンドルします。これはデフォルトで自動的に、かつ透過的に行われます。

その理由は?

これは、Vite が「依存関係の事前バンドル」を実行しています。

このプロセスには 2 つの目的があります:

  1. CommonJS と UMD の互換性: 開発中の Vite のコードは ECMAScript モジュールとして提供しています。そのため、Vite は、CommonJS または、UMD を ESM に変換する必要があります。CommonJS の依存関係を変換する場合、Vite はインポート文をスマート分析を実行してエクスポートが動的に割り当てられていても、CommonJS モジュールは期待通りに動作します。(例 React):
js
   // works as expected
   import React, { useState } from 'react'
  1. パフォーマンス: 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.includebuild.commonjsOptions.include に依存関係を追加して、設定することができます。

js
export default 
defineConfig
({
optimizeDeps
: {
include
: ['linked-dep'],
},
build
: {
commonjsOptions
: {
include
: [/linked-dep/, /node_modules/],
}, }, })

リンクされた依存関係を変更する場合は、--force コマンドラインオプションを指定して開発サーバーを再起動すると、変更が有効になります。

挙動のカスタマイズ

デフォルトのヒューリスティックな方法による依存関係の発見によって、必ずしも望ましい結果が得られるとは限りません。リストから依存関係を明示的に含めたり除外したりする場合は、optimizeDeps 設定オプションを使用してください。

optimizeDeps.include または optimizeDeps.exclude の一般的な使用例は、ソースコードで直接検出できないインポートがある場合です。たとえば、インポートはプラグイン変換の結果として作成される可能性があります。これは、Vite が最初のスキャンでインポートを検出できないことを意味します。つまり、ファイルがブラウザーによって要求されて変換された後にのみ、インポートを検出できます。 これにより、サーバーの起動後すぐにサーバーが再バンドルされます。

これには、includeexclude の両方が使用できます。依存関係が大きい(多くの内部モジュールがある)場合や、CommonJS の場合には、それを含める必要があります。依存関係が小さく、すでに有効な ESM の場合には、それを除外し、ブラウザーに直接読み込ませることができます。

esbuild も optimizeDeps.esbuildOptions オプションでさらにカスタマイズできます。例えば、esbuild のプラグインを追加して、依存関係にある特殊なファイルを扱えるようにするか、build target を変更します。

キャッシュ

File System キャッシュ

Vite は、node_modules/.vite に、事前バンドル済みの依存関係をキャッシュします。いくつかのソースに基づいて、事前バンドルを再実行する必要があるかどうか決定します:

  • パッケージマネージャーのロックファイルの内容、例: package-lock.jsonyarn.lockpnpm-lock.yamlbun.lockb など。
  • もし存在すれば、vite.config.js の関連するフィールド。
  • パッチフォルダーの変更時間。
  • NODE_ENV の値。

上記のいずれかが変更された場合のみ、事前バンドルを再実行する必要があります。

何らかの理由で Vite に再バンドルを強制したい場合は、開発サーバーを --force コマンドラインオプションで起動するか、手動で node_modules/.vite のキャッシュディレクトリーを削除します。

ブラウザーキャッシュ

解決された依存関係のリクエストは、開発中のページの再読み込みのパフォーマンスを向上させるために、HTTP ヘッダー max-age = 31536000、immutable で積極的にキャッシュされます。一度キャッシュされると、これらのリクエストは開発サーバーに再び到達することはありません。異なるバージョンがインストールされた(パッケージマネージャーのロックファイルに反映された)場合は、付与されているバージョンクエリーによって自動的に無効になります。ローカルでの編集で依存関係をデバッグしたい場合は、以下のように行えます:

  1. ブラウザーの devtools のネットワークタブからキャッシュを一時的に無効にします。
  2. Vite 開発サーバーを --force フラグで再起動して、依存関係を再バンドルします。
  3. ページをリロードします。

Released under the MIT License. (081e811d)