Механизм optimizeDeps в Vite отвечает за предварительную
оптимизацию зависимостей во время запуска dev-сервера. Эта оптимизация
выполняется через esbuild и предназначена для ускорения
холодного старта проекта, уменьшения количества HTTP-запросов и
ускорения обработки CommonJS-модулей.
По умолчанию Vite автоматически анализирует импортируемые зависимости и самостоятельно определяет, какие пакеты необходимо предобработать. Однако автоматическое определение работает не всегда корректно. Некоторые зависимости могут:
Для подобных случаев существует параметр
optimizeDeps.include.
import { defineConfig } from 'vite'
export default defineConfig({
optimizeDeps: {
include: ['lodash', 'axios']
}
})
Все зависимости, перечисленные в массиве include, будут
принудительно включены в этап предварительной оптимизации.
Во время запуска dev-сервера Vite:
esbuild..vite.optimizeDeps.include вмешивается в этот процесс и
говорит Vite:
«Оптимизируй эти зависимости независимо от результатов автоматического анализа».
Это особенно важно для зависимостей, которые не обнаруживаются статическим анализатором.
Vite плохо определяет зависимости внутри динамически формируемых строк.
Проблемный пример:
const moduleName = 'lodash'
const lib = await import(moduleName)
Статический анализ здесь невозможен.
Решение:
export default defineConfig({
optimizeDeps: {
include: ['lodash']
}
})
if (window.innerWidth > 1000) {
import('chart.js')
}
Во время анализа Vite может не включить пакет в pre-bundling.
Принудительное включение:
optimizeDeps: {
include: ['chart.js']
}
import api from '@shared/api'
Если alias указывает на пакет внутри workspace или symlink-зависимость, Vite может пропустить оптимизацию.
В monorepo-проектах часто используются локальные пакеты:
packages/
ui/
core/
app/
Пакет может подключаться как:
import { Button } from '@company/ui'
Однако Vite воспринимает workspace-пакет как исходный код, а не dependency.
Иногда это приводит к:
Решение:
optimizeDeps: {
include: ['@company/ui']
}
Во время оптимизации Vite создаёт единый ESM-бандл зависимости.
Например:
import _ from 'lodash'
может быть преобразован во внутренний файл:
node_modules/.vite/deps/lodash.js
Этот файл:
Некоторые библиотеки публикуются только как CommonJS:
const moment = require('moment')
Vite автоматически конвертирует их через esbuild, но
иногда пакет пропускается анализатором.
Пример:
optimizeDeps: {
include: ['moment']
}
Крупные библиотеки компонентов:
antdelement-plusprimevuevuetifyмогут содержать множество вложенных импортов.
Предварительная оптимизация уменьшает нагрузку на dev-сервер.
optimizeDeps: {
include: ['antd']
}
Например:
import debounce from 'lodash/debounce'
или:
import { format } from 'date-fns'
Без pre-bundling браузер может получать десятки отдельных модулей.
Vite позволяет указывать вложенные entry-point.
Пример:
optimizeDeps: {
include: [
'lodash/debounce',
'lodash/throttle'
]
}
Это особенно важно для библиотек с tree-shaking-структурой.
Некоторые плагины генерируют виртуальные модули:
virtual:my-module
или скрытые импорты.
Например, плагины для:
Автоматический анализатор может не увидеть реальные зависимости.
В этом случае пакеты подключаются вручную:
optimizeDeps: {
include: [
'graphql',
'vue-i18n'
]
}
Это принципиально разные механизмы.
Используется только:
Цель:
Используется:
Пример:
build: {
rollupOptions: {
external: ['vue']
}
}
Принудительно оптимизирует зависимость.
include: ['axios']
Запрещает оптимизацию.
exclude: ['my-library']
Некоторые пакеты:
Тогда их исключают:
optimizeDeps: {
exclude: ['problematic-lib']
}
Некоторые библиотеки активно используют deep import:
import Button from 'library/components/Button'
Каждый deep import может стать отдельным HTTP-запросом.
Vite позволяет заранее оптимизировать их:
optimizeDeps: {
include: [
'library/components/Button',
'library/components/Input'
]
}
Если используется npm link, pnpm link или
symlink-зависимости, Vite может считать пакет исходным кодом
приложения.
Следствия:
Принудительное включение помогает:
optimizeDeps: {
include: ['shared-lib']
}
При использовании SSR часть зависимостей должна быть предобработана отдельно.
Например:
export default defineConfig({
optimizeDeps: {
include: ['some-cjs-package']
},
ssr: {
noExternal: ['some-cjs-package']
}
})
Менеджер пакетов pnpm использует symlink-структуру
node_modules.
Из-за этого некоторые зависимости:
Особенно часто проблема возникает с:
В больших React-проектах часто оптимизируют:
optimizeDeps: {
include: [
'react',
'react-dom',
'react/jsx-runtime'
]
}
Это уменьшает количество отдельных модулей во время разработки.
Для Vue-проектов:
optimizeDeps: {
include: [
'vue',
'vue-router',
'pinia'
]
}
Особенно полезно в monorepo.
TypeScript напрямую не влияет на optimizeDeps, поскольку анализ выполняется после разрешения импортов.
Однако indirect imports через:
могут мешать автоматическому обнаружению зависимостей.
Без pre-bundling:
С include:
Чрезмерное количество зависимостей в include может:
Плохой пример:
include: [
'lodash',
'rxjs',
'three',
'd3',
'monaco-editor',
'firebase'
]
если половина библиотек почти не используется.
После запуска dev-сервера Vite создаёт каталог:
node_modules/.vite
или:
node_modules/.vite/deps
Там находятся оптимизированные зависимости.
После изменения optimizeDeps иногда требуется очистка:
rm -rf node_modules/.vite
или запуск:
vite --force
Флаг --force заставляет Vite пересоздать pre-bundle.
import { defineConfig } from 'vite'
export default defineConfig({
optimizeDeps: {
include: [
'axios',
'lodash',
'vue-i18n',
'@company/ui',
'chart.js'
],
exclude: [
'legacy-lib'
]
}
})
Часто наблюдаются:
Типичный пример:
Failed to resolve entry for package
или:
does not provide an export named
Часто решается через:
optimizeDeps: {
include: ['problem-package']
}
Во время pre-bundling Vite использует:
optimizeDeps.include добавляет зависимости напрямую в
graph preprocessing phase до запуска основного dev pipeline.
Это гарантирует:
import { defineConfig } from 'vite'
export default defineConfig({
optimizeDeps: {
include: [
'@workspace/ui',
'@workspace/utils',
'@workspace/icons'
]
}
})
Преимущества:
export default defineConfig({
optimizeDeps: {
include: [
'react',
'react-dom',
'scheduler',
'react/jsx-runtime'
]
}
})
Это помогает избежать:
export default defineConfig({
optimizeDeps: {
include: [
'monaco-editor',
'chart.js',
'highlight.js'
]
}
})
Такие библиотеки часто загружают внутренние модули динамически и плохо анализируются автоматически.
Во многих небольших проектах Vite прекрасно работает без ручной настройки.
Автоматического анализа достаточно, если:
Ручная настройка требуется преимущественно в крупных или нестандартных проектах.