Skip to content

Beyond Fast

ViteConf 2023

Watch the replay!

Предварительное связывание зависимостей

Когда вы запускаете vite в первый раз, Vite предварительно объединяет зависимости вашего проекта перед локальной загрузкой вашего сайта. По умолчанию это делается автоматически и прозрачно.

Почему

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

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

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

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

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

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

ПРИМЕЧАНИЕ

Предварительное связывание зависимостей применяется только в режиме разработки и использует esbuild для преобразования зависимостей в ESM. В производственных сборках вместо этого используется @rollup/plugin-commonjs.

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

Если существующий кеш не найден, Vite просканирует ваш исходный код и автоматически обнаружит импорт зависимостей (т. е. "bare imports", который должен быть разрешен из node_modules) и использует этот найденный импорт в качестве точек входа для предварительного пакета. Предварительная сборка выполняется с помощью esbuild, поэтому обычно это происходит очень быстро.

После запуска сервера, если обнаружится новый импорт зависимостей, которого еще нет в кеше, Vite повторно запустит процесс связывания dep и при необходимости перезагрузит страницу.

Монорепозитории и связанные зависимости

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

Однако для этого необходимо, чтобы связанное отложение было экспортировано как ESM. Если нет, вы можете добавить зависимость в optimizeDeps.include и build.commonjsOptions.include в вашей конфигурации.

js
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 для обработки специальных файлов в зависимостях или изменив сборку target.

Кэширование

Кэш файловой системы

Vite кэширует предварительно связанные зависимости в node_modules/.vite. Он определяет, нужно ли повторно запустить этап предварительной сборки на основе нескольких источников:

  • Содержимое файла блокировки менеджера пакетов, например, package-lock.json, yarn.lock, pnpm-lock.yaml или bun.lockb.
  • Исправлено время модификации папки.
  • Соответствующие поля в вашем vite.config.js, если они есть.
  • Значение NODE_ENV.

Шаг предварительной сборки нужно будет повторить только в том случае, если что-то из вышеперечисленного изменилось.

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

Кэш браузера

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

  1. Временно отключите кеш через вкладку «Сеть» вашего браузера devtools;
  2. Перезапустите сервер разработки Vite с флагом --force, чтобы повторно связать deps;
  3. Перезагрузите страницу.

Выпущено под лицензией MIT. (dev)