Настройки build: target, outDir, assetsDir

Параметр build.target определяет, в какой стандарт JavaScript и какие браузеры должен компилироваться итоговый код приложения. От этого зависит:

  • какие современные возможности языка останутся в сборке;
  • насколько старые браузеры смогут запускать приложение;
  • объём итогового бандла;
  • необходимость транспиляции новых конструкций.

По умолчанию Vite ориентируется на современные браузеры с поддержкой ES-модулей. Однако во многих проектах требуется явно задавать целевую среду.

Базовый пример:

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'es2015'
    }
})

В данном случае итоговый код будет преобразован под стандарт ECMAScript 2015.


Поддерживаемые значения target

Строковое значение стандарта ECMAScript

Наиболее распространённый вариант:

build: {
    target: 'es2017'
}

Популярные значения:

Значение Описание
es2015 Поддержка старых браузеров
es2016 Включает Array.includes()
es2017 Async/await
es2018 Асинхронные итераторы
es2019 flat(), flatMap()
es2020 Optional chaining, nullish coalescing
es2021 Logical assignment
es2022 Top-level await
esnext Без транспиляции современных возможностей

Использование esnext

Режим esnext отключает большинство преобразований.

build: {
    target: 'esnext'
}

Особенности:

  • минимальное вмешательство в код;
  • более быстрая сборка;
  • меньший размер бандла;
  • подходит только для современных браузеров.

Такой режим часто используется:

  • во внутренних корпоративных системах;
  • в Electron-приложениях;
  • в современных Chromium WebView;
  • в проектах без поддержки legacy-браузеров.

Указание браузеров

Vite позволяет задавать список конкретных браузеров.

build: {
    target: ['chrome90', 'firefox88']
}

Пример:

build: {
    target: [
        'chrome87',
        'edge88',
        'firefox78',
        'safari13'
    ]
}

В этом случае esbuild будет ориентироваться именно на указанные браузеры.


Как target влияет на код

Исходный код:

const title = user?.profile?.name ?? 'Guest'

При современном target:

build: {
    target: 'es2020'
}

код практически не изменится.

При старом target:

build: {
    target: 'es2015'
}

optional chaining и nullish coalescing будут преобразованы в более совместимый код.


Влияние на размер сборки

Чем современнее target:

  • тем меньше транспиляции;
  • тем компактнее итоговый код;
  • тем быстрее работает приложение.

Например:

build: {
    target: 'esnext'
}

может дать существенно меньший бандл, чем:

build: {
    target: 'es2015'
}

поскольку старые конструкции требуют дополнительных преобразований.


Ограничения target

Параметр target:

  • не добавляет полифилы;
  • не исправляет отсутствие API браузера;
  • влияет только на синтаксис и часть трансформаций.

Например:

Array.prototype.flatMap
Promise.any
fetch

не будут автоматически полифилиться.

Для поддержки таких возможностей используются:

  • core-js;
  • @vitejs/plugin-legacy;
  • собственные полифилы.

Использование @vitejs/plugin-legacy

Для старых браузеров одного target недостаточно.

Пример:

npm install @vitejs/plugin-legacy

Конфигурация:

import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'

export default defineConfig({
    plugins: [
        legacy({
            targets: ['defaults', 'not IE 11']
        })
    ]
})

Плагин:

  • генерирует legacy-бандлы;
  • добавляет polyfills;
  • обеспечивает совместимость со старыми браузерами.

Параметр build.outDir

outDir определяет директорию, в которую будет записана итоговая сборка.

По умолчанию:

dist

Базовый пример:

build: {
    outDir: 'build'
}

После сборки структура будет выглядеть так:

project/
├─ build/
│  ├─ assets/
│  ├─ index.html
│  └─ ...

Использование абсолютного пути

Можно указывать абсолютный путь:

build: {
    outDir: '/var/www/project'
}

Однако чаще используются относительные директории внутри проекта.


Разделение сборок

Иногда проект генерирует несколько видов сборок.

Пример:

build: {
    outDir: 'dist/client'
}

или:

build: {
    outDir: 'dist/admin'
}

Это удобно:

  • для монорепозиториев;
  • для multi-app архитектуры;
  • для SSR;
  • для CI/CD пайплайнов.

Очистка директории перед сборкой

Перед созданием новой сборки Vite автоматически очищает outDir.

Пример:

build: {
    outDir: 'dist'
}

Старая директория будет удалена перед записью новых файлов.


Параметр emptyOutDir

Автоматическую очистку можно отключить.

build: {
    emptyOutDir: false
}

Это бывает полезно:

  • при частичной генерации файлов;
  • при работе с внешними артефактами;
  • при ручном управлении ассетами.

Предупреждение при выходе за пределы проекта

Если outDir находится вне корня проекта:

build: {
    outDir: '../public'
}

Vite покажет предупреждение.

Это защита от случайного удаления файлов при очистке директории.


Интеграция с backend-framework

Очень распространён сценарий, когда сборка сразу складывается в backend-проект.

Пример для PHP:

build: {
    outDir: '../public/assets'
}

или:

build: {
    outDir: '../www/build'
}

Подобная схема активно используется:

  • в Laravel;
  • в Symfony;
  • в Bitrix;
  • в Express;
  • в Django;
  • в ASP.NET.

Параметр build.assetsDir

assetsDir определяет папку внутри outDir, куда складываются статические ресурсы.

По умолчанию:

assets

Пример:

build: {
    assetsDir: 'static'
}

Структура:

dist/
├─ static/
│  ├─ index-abc123.js
│  ├─ style-xyz456.css
│  └─ logo-123.png
└─ index.html

Какие файлы попадают в assetsDir

Обычно туда помещаются:

  • JavaScript;
  • CSS;
  • изображения;
  • шрифты;
  • SVG;
  • media-файлы.

Изменение структуры проекта

Пример:

build: {
    outDir: 'public',
    assetsDir: 'resources'
}

Результат:

public/
├─ resources/
│  ├─ app.js
│  ├─ app.css
│  └─ ...
└─ index.html

Полное отключение папки assets

Иногда требуется хранить файлы прямо в корне сборки.

build: {
    assetsDir: ''
}

Тогда структура станет такой:

dist/
├─ app.js
├─ app.css
├─ logo.png
└─ index.html

Однако такой подход может привести:

  • к захламлению директории;
  • к конфликтам имён;
  • к ухудшению структуры проекта.

Использование CDN-структуры

assetsDir часто используется вместе с CDN.

Пример:

build: {
    assetsDir: 'cdn'
}

или:

build: {
    assetsDir: 'static/assets'
}

Это позволяет организовать структуру файлов под инфраструктуру сервера.


Связь outDir и assetsDir

assetsDir всегда считается относительно outDir.

Пример:

build: {
    outDir: 'build',
    assetsDir: 'files'
}

Результат:

build/
├─ files/
│  ├─ app.js
│  └─ style.css
└─ index.html

Настройка production-сборки

Типичная production-конфигурация:

import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'es2018',
        outDir: 'dist',
        assetsDir: 'assets'
    }
})

Конфигурация для старых браузеров

import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'es2015',
        outDir: 'build',
        assetsDir: 'static'
    }
})

Конфигурация для современных браузеров

import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'esnext',
        outDir: 'release',
        assetsDir: 'bundle'
    }
})

Конфигурация для backend-интеграции

import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'es2017',
        outDir: '../public/build',
        assetsDir: 'assets'
    }
})

Ошибки при настройке target

Слишком старый target

target: 'es5'

Vite не ориентирован на полноценную поддержку ES5.

Для старых браузеров рекомендуется использовать:

  • @vitejs/plugin-legacy;
  • Babel;
  • polyfills.

Использование unsupported browser features

Даже при:

target: 'es2015'

некоторые API могут не работать без полифилов.


Конфликт путей

Ошибочная конфигурация:

build: {
    outDir: '/',
}

или:

build: {
    outDir: '../'
}

может привести к удалению лишних файлов при очистке директории.


Практические рекомендации

Для современных SPA

build: {
    target: 'es2020'
}

Для корпоративных legacy-систем

build: {
    target: 'es2015'
}

вместе с:

@vitejs/plugin-legacy

Для Electron

build: {
    target: 'chrome120'
}

Для максимальной производительности

build: {
    target: 'esnext'
}

Итоговая комплексная конфигурация

import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'es2018',

        outDir: 'dist',

        assetsDir: 'assets',

        emptyOutDir: true
    }
})

Такая конфигурация:

  • создаёт production-сборку;
  • сохраняет совместимость с большинством современных браузеров;
  • поддерживает аккуратную структуру файлов;
  • подходит для большинства frontend-проектов на Vite.