Функция mergeConfig в Vite предназначена для объединения
нескольких конфигурационных объектов Vite в один итоговый конфиг. На
практике она используется при создании плагинов, библиотек, внутренних
CLI-инструментов, корпоративных шаблонов и многослойных
конфигураций.
mergeConfig позволяет:
Наиболее часто функция применяется в экосистемных инструментах поверх Vite.
import { mergeConfig } from 'vite'
Функция принимает два объекта:
mergeConfig(configA, configB)
Второй конфиг расширяет первый.
Пример:
import { mergeConfig } from 'vite'
const baseConfig = {
server: {
port: 3000
}
}
const customConfig = {
server: {
host: true
}
}
const config = mergeConfig(baseConfig, customConfig)
console.log(config)
Результат:
{
server: {
port: 3000,
host: true
}
}
Без mergeConfig пришлось бы вручную объединять вложенные
объекты.
Обычный оператор spread работает только на верхнем уровне:
const config = {
...baseConfig,
...customConfig
}
Если оба объекта содержат server, второй объект
полностью перезапишет первый:
{
server: {
host: true
}
}
Свойство port исчезнет.
mergeConfig выполняет глубокое объединение вложенных
структур.
resolve.aliasОдна из самых частых задач — расширение алиасов.
Базовая конфигурация:
const baseConfig = {
resolve: {
alias: {
'@': '/src'
}
}
}
Дополнительная:
const testConfig = {
resolve: {
alias: {
'@mocks': '/tests/mocks'
}
}
}
Объединение:
const config = mergeConfig(baseConfig, testConfig)
Результат:
{
resolve: {
alias: {
'@': '/src',
'@mocks': '/tests/mocks'
}
}
}
defineconst baseConfig = {
define: {
__DEV__: true
}
}
const prodConfig = {
define: {
__API_URL__: '"https://api.site.com"'
}
}
const config = mergeConfig(baseConfig, prodConfig)
Результат:
{
define: {
__DEV__: true,
__API_URL__: '"https://api.site.com"'
}
}
mergeConfig не всегда просто заменяет массивы. Для
некоторых структур используется специальная логика.
Пример с плагинами:
const baseConfig = {
plugins: [
react()
]
}
const customConfig = {
plugins: [
legacy()
]
}
Результат:
{
plugins: [
react(),
legacy()
]
}
Массивы плагинов объединяются.
const baseConfig = {
build: {
rollupOptions: {
external: ['vue']
}
}
}
const libConfig = {
build: {
rollupOptions: {
external: ['react']
}
}
}
После объединения:
{
build: {
rollupOptions: {
external: ['vue', 'react']
}
}
}
Это особенно важно при создании библиотек.
defineConfigНаиболее распространённый сценарий:
import { defineConfig, mergeConfig } from 'vite'
const baseConfig = defineConfig({
server: {
port: 3000
}
})
export default mergeConfig(baseConfig, {
server: {
host: true
}
})
// vite.base.js
export default {
resolve: {
alias: {
'@': '/src'
}
}
}
// vite.dev.js
export default {
server: {
port: 5173
}
}
// vite.prod.js
export default {
build: {
minify: 'esbuild'
}
}
import { mergeConfig } from 'vite'
import baseConfig from './vite.base'
import devConfig from './vite.dev'
export default mergeConfig(baseConfig, devConfig)
Можно строить многоуровневую конфигурацию.
const config = mergeConfig(
baseConfig,
mergeConfig(
frameworkConfig,
userConfig
)
)
Порядок имеет значение.
Последний конфиг имеет приоритет.
Если свойства конфликтуют:
const a = {
server: {
port: 3000
}
}
const b = {
server: {
port: 8080
}
}
Результат:
{
server: {
port: 8080
}
}
Значение из второго конфига перезаписывает первое.
Многие плагины Vite динамически расширяют конфигурацию через
mergeConfig.
Пример:
import { mergeConfig } from 'vite'
export default function customPlugin() {
return {
name: 'custom-plugin',
config(userConfig) {
return mergeConfig(userConfig, {
define: {
__CUSTOM__: true
}
})
}
}
}
import { defineConfig, mergeConfig } from 'vite'
const baseConfig = {
resolve: {
alias: {
'@': '/src'
}
}
}
const devConfig = {
server: {
port: 3000
}
}
const prodConfig = {
build: {
sourcemap: false
}
}
export default defineConfig(({ mode }) => {
if (mode === 'development') {
return mergeConfig(baseConfig, devConfig)
}
return mergeConfig(baseConfig, prodConfig)
})
const baseConfig = {
server: {
port: 3000,
open: true
}
}
const localConfig = {
server: {
host: '0.0.0.0'
}
}
После объединения:
{
server: {
port: 3000,
open: true,
host: '0.0.0.0'
}
}
optimizeDepsconst baseConfig = {
optimizeDeps: {
include: ['axios']
}
}
const uiConfig = {
optimizeDeps: {
include: ['lodash']
}
}
Результат:
{
optimizeDeps: {
include: ['axios', 'lodash']
}
}
В монорепозиториях mergeConfig используется особенно
часто.
// configs/vite.base.js
export default {
resolve: {
alias: {
'@shared': '/packages/shared'
}
}
}
// apps/admin/vite.config.js
import { mergeConfig } from 'vite'
import baseConfig from '../. ./configs/vite.base'
export default mergeConfig(baseConfig, {
server: {
port: 4000
}
})
При использовании тестовых окружений:
const viteConfig = {
resolve: {
alias: {
'@': '/src'
}
}
}
const testConfig = {
test: {
globals: true
}
}
const config = mergeConfig(viteConfig, testConfig)
Экосистема Vitest активно использует mergeConfig.
import { mergeConfig } from 'vite'
import viteConfig from './vite.config'
export default mergeConfig(viteConfig, {
test: {
environment: 'jsdom'
}
})
Object.assignObject.assignObject.assign(a, b)
Особенности:
mergeConfigОсобенности:
Упрощённо алгоритм выглядит так:
Проверяется тип значения.
Если значение — объект:
Если значение — массив:
Если значение примитивное:
plugins: [
react(),
react()
]
mergeConfig не удаляет дубликаты автоматически.
alias: {
'@': '/src'
}
и
alias: {
'@': '/app'
}
Результат:
alias: {
'@': '/app'
}
Последний конфиг перезапишет предыдущий.
Некоторые массивы объединяются, а некоторые заменяются в зависимости от внутренней стратегии Vite.
Поэтому при сложных конфигурациях важно проверять итоговый объект.
// configs/base.js
export default {
resolve: {
alias: {
'@': '/src'
}
}
}
// configs/react.js
import react from '@vitejs/plugin-react'
export default {
plugins: [react()]
}
// configs/prod.js
export default {
build: {
sourcemap: false,
minify: 'esbuild'
}
}
import { mergeConfig } from 'vite'
import base from './configs/base'
import react from './configs/react'
import prod from './configs/prod'
export default mergeConfig(
base,
mergeConfig(
react,
prod
)
)
mergeConfig особенно полезенОдин базовый конфиг используется во множестве проектов.
CLI генерирует часть конфига автоматически.
Плагин расширяет пользовательскую конфигурацию без полного перезаписывания.
Каждый пакет наследует общую конфигурацию.
Конфиг собирается из независимых модулей.
mergeConfigconst config = {
...baseConfig,
server: {
...baseConfig.server,
...customConfig.server
}
}
При большом количестве вложенности код быстро становится трудно поддерживаемым.
mergeConfigconst config = mergeConfig(baseConfig, customConfig)
Код компактнее, безопаснее и лучше масштабируется.
import { defineConfig, mergeConfig } from 'vite'
const baseConfig = {
server: {
port: 3000
}
}
export default defineConfig(async () => {
const remoteConfig = await loadConfig()
return mergeConfig(baseConfig, remoteConfig)
})
function createConfig(userConfig = {}) {
const systemConfig = {
build: {
sourcemap: true
}
}
return mergeConfig(systemConfig, userConfig)
}
import { mergeConfig, type UserConfig } from 'vite'
const baseConfig: UserConfig = {
server: {
port: 3000
}
}
const customConfig: UserConfig = {
build: {
sourcemap: true
}
}
export default mergeConfig(baseConfig, customConfig)
mergeConfigmergeConfig является одним из ключевых механизмов
масштабирования конфигурации в Vite. Через него строятся:
Без mergeConfig поддержка крупных конфигураций Vite
быстро превращается в сложную систему ручного копирования и перезаписи
свойств.