Pre-Bundling зависимостей

Когда вы запускаете vite в первый раз, вы можете увидеть это сообщение:

Optimizable dependencies detected:
react, react-dom
Pre-bundling them to speed up dev server page load...
(this will be run only when your dependencies have changed)

Почему

Vite выполняет то, что мы называем "dependency pre-bundling" (предварительное объединение зависимостей). Этот процесс служит двум целям:

  1. CommonJS и UMD совместимость: Во время разработки, Vite's dev обрабатывает весь код как нативный ESM. Следовательно, Vite должен сначала конвертировать зависимости, которые поставляются как CommonJS или UMD в ESM.

    При преобразовании зависимостей CommonJS Vite выполняет интеллектуальный анализ импорта, поэтому именование импорта в модулях CommonJS будет работать должным образом, даже если экспорт назначается динамически (например, React):

    // работает как ожидается
    import React, { useState } from 'react'
    
  2. Производительность: Vite конвертирует ESM зависимости со множеством внутренних модулей в один модуль, чтобы улучшить последующую скорость загрузки страниц.

    Некоторые пакеты поставляются как сборка множества отдельных ES модулей, импортирующих друг друга. Например, lodash-es имеет более 600 внутренних модулей! Когда мы делаем import { debounce } from 'lodash-es', браузер запускает 600+ HTTP запросов одновременно! Несмотря на то, что у сервера нет проблема с их обработкой, огромное количество запросов создаёт перегрузку сети на стороне браузера, в результате чего страница загружается гораздо медленнее.

    С pre-bundling lodash-es в один модуль, нам нужно сделать только один HTTP запрос!

Автоматическое обнаружение зависимостей

Если кеша ещё нет, то Vite проанализирует ваш исходный код и автоматически обнаружит импорт зависимостей (то есть "bare imports", которые должны браться из node_modules) и будет использовать найденные импорты как точки входа (entry points) для pre-bundle. Pre-bundling осуществляется с помощью esbuild, поэтому всё это происходит очень быстро.

После того как сервер запущен, если обнаружен новый импорт зависимости (dependency import), который не в кеше, то Vite перезапустит сборку зависимостей (dep bundling process) и перезагрузит страницу.

Монорепы и связанные зависимости (Monorepos and Linked Dependencies)

В монорепах, зависимости могут быть связанным пакетом (linked package) того же репо. Vite автоматически находит зависимости, которые берутся не из node_modules и рассматривает их как исходный код. Он не будет пытаться собрать (linked dep) связанную зависимость, вместо этого он будет анализировать список связанных зависимостей.

Note

Связанные зависимости (linked dependencies) могут работать некорректно в финальной сборке из-за различий в разрешении зависимостей (dependency resolution). Вместо этого, используйте npm package для всех локальных зависимостей, чтобы избежать ошибок в финальной сборке.

Настройка

Дефолтная эвристика для поиска зависимостей не всегда может соответствовать вашим ожиданиям. Если вы хотите явно подключить/отключить зависимости из списка, воспользуйтесь optimizeDeps config options.

Типичный вариант использования optimizeDeps.include или optimizeDeps.exclude - когда у вас есть импорт, который нельзя напрямую обнаружить в исходном коде. Например, может быть этот импорт создаётся как результат трансформации какого-то плагина. Это значит, Vite не сможет найти импорт при начальном сканировании - он может обнаружить импорт только после того, как файл запрошен браузером и трансформирован. Это приведёт к немедленному re-bundle (пересборке) после запуска сервера.

Оба параметра include и exclude могут быть использованы, чтобы решить этот вопрос. Если зависимость большая (с большим количеством внутренних модулей) или это CommonJS, то Вам следует подключить это (include); Если зависимость маленькая и это уже валидный ESM, вы можете исключить (exclude) это и позволить браузеру загрузить это напрямую.

Кэширование

File System Cache

Vite кэширует pre-bundled зависимости в node_modules/.vite. Он определяет нужно ли делать re-run (перезапускать) pre-bundling, основываясь на следующих данных:

  • Список зависимостей dependencies в вашем package.json
  • Package manager lockfiles, например. package-lock.json, yarn.lock, или pnpm-lock.yaml.
  • Соответствующие конфиг поля в vite.config.js, если они есть.

Pre-bundling должен будет повторно запуститься (re-run) когда один из вышеуказанных пунктов изменится.

Если по какой-то причине Вы хотите, чтобы Vite пересобрал зависимости (re-bundle deps), Вы можете запустить dev сервер с параметром --force или вручную удалить папку node_modules/.vite.

Browser Cache

Резолвнутые (найденные и обработанные) запросы зависимостей жёстко кэшируются с помощью HTTP заголовков max-age=31536000,immutable, чтобы улучшить производительность перезагрузки страниц во время разработки. Закэшировавшись один раз, эти запросы больше никогда не будут грузиться на dev сервер снова. Они автоматически удалятся из кеша с помощью добавленной версии в query параметрах, если установлена другая версия (как это отражено в вашем package manager lockfile). Если Вы хотите продебажить ваши зависимости при помощи локальных изменений, Вы можете сделать следующее:

  1. Временно заблокируйте кэш через вкладку Network в devtools браузера;
  2. Перезапустите Vite dev сервер с флагом --force чтобы пересобрать зависимости (re-bundle the deps);
  3. Перезагрузите страницу.