Двухрежимная архитектура: dev и production

Архитектура Vite построена вокруг двух полностью разных сценариев работы:

  • режима разработки (development)
  • режима production-сборки (production build)

В отличие от старых bundler-систем, где один и тот же механизм использовался и для разработки, и для финальной сборки, Vite разделяет эти процессы на уровне архитектуры.

Это позволяет одновременно получить:

  • практически мгновенный запуск dev-сервера
  • быстрый HMR
  • минимальную нагрузку во время разработки
  • высокооптимизированный production-бандл

Ключевая идея Vite заключается в том, что разработка и production имеют разные требования, поэтому их нельзя эффективно обслуживать одной и той же системой.


Проблема классических bundler-подходов

До появления Vite большинство инструментов работали по схеме:

  1. Все файлы проекта анализируются
  2. Формируется dependency graph
  3. Выполняется bundling
  4. Генерируется единый набор бандлов
  5. Только после этого запускается dev-сервер

Даже при изменении одного файла приходилось:

  • пересобирать часть графа зависимостей
  • обновлять bundle
  • инвалидировать кэш
  • заново генерировать модули

На небольших проектах это было незаметно, но крупные SPA-приложения сталкивались с проблемами:

  • медленный cold start
  • долгий rebuild
  • тормозящий HMR
  • высокая нагрузка на CPU

Разделение dev и production

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

Development Mode

Во время разработки Vite:

  • не создает production bundle
  • не выполняет полный bundling
  • не собирает приложение заранее

Вместо этого используется:

  • native ES Modules
  • dev server
  • on-demand compilation

Браузер сам загружает нужные модули.


Production Mode

Во время production-сборки Vite:

  • выполняет полноценный bundling
  • оптимизирует код
  • минифицирует ресурсы
  • разбивает chunks
  • tree-shaking
  • code splitting
  • asset optimization

Для этого используется Rollup.


Архитектура режима разработки

Native ESM

Главная особенность Vite dev-режима — использование ES-модулей браузера.

Например:

import { createApp } from './app.js'
import { router } from './router.js'
import './styles/main.css'

Браузер сам делает запросы:

GET /app.js
GET /router.js
GET /styles/main.css

Vite лишь перехватывает запросы и трансформирует файлы при необходимости.


Отсутствие полного bundling

Во время разработки Vite не объединяет проект в bundle.

Это фундаментальное отличие от Webpack.

Вместо:

src → build graph → bundle → serve

используется:

browser requests module → Vite transforms module → response

On-Demand Transformation

Трансформация происходит только по запросу.

Если модуль никогда не был импортирован:

import './admin-panel.js'

то Vite не будет его обрабатывать до первого запроса.

Это радикально уменьшает время запуска проекта.


Dev Server как middleware-система

Vite dev server — это HTTP-сервер с middleware-архитектурой.

Он выполняет:

  • обработку модулей
  • трансформацию TypeScript
  • обработку Vue/Svelte/React
  • HMR
  • обработку CSS
  • обработку ассетов

Жизненный цикл запроса в dev-режиме

1. Браузер делает запрос

Например:

GET /src/main.js

2. Vite определяет тип файла

Сервер анализирует:

  • JS
  • TS
  • JSX
  • TSX
  • CSS
  • Vue SFC
  • JSON

3. Выполняется transform pipeline

Применяются:

  • плагины
  • esbuild
  • framework transformers

4. Генерируется ESM-код

Например:

Исходник:

const message: string = 'Hello'

После transform:

const message = 'Hello'

5. Код отправляется браузеру

Браузер выполняет модуль напрямую.


Почему dev-режим работает быстро

Нет полной сборки

Самая дорогая операция bundler-систем отсутствует.


Использование браузерного ESM

Работа по загрузке модулей делегируется браузеру.


esbuild для трансформаций

Vite использует esbuild для:

  • TypeScript
  • JSX
  • TSX

esbuild написан на Go и значительно быстрее Babel.


Частичная обработка проекта

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


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

Несмотря на ESM-подход, npm-зависимости создают проблему.

Многие библиотеки:

  • публикуются в CommonJS
  • содержат тысячи мелких модулей
  • не оптимизированы под native ESM

Dependency Pre-Bundling

Для решения проблемы Vite использует pre-bundling.

Во время первого запуска:

vite

Vite:

  1. анализирует зависимости
  2. объединяет их через esbuild
  3. кеширует результат

Пример

Без pre-bundling:

lodash-es/
  map.js
  filter.js
  reduce.js
  ...

Браузер может отправить сотни запросов.

После оптимизации:

node_modules/.vite/deps/

Создаются оптимизированные ESM-файлы.


Кэширование dev-режима

Vite активно использует файловый кэш.

Каталог:

node_modules/.vite

содержит:

  • pre-bundled dependencies
  • metadata
  • optimized chunks

Это позволяет избежать повторной обработки.


HMR в архитектуре Vite

Hot Module Replacement

Vite реализует HMR поверх ESM.

Когда файл изменяется:

  1. определяется affected module
  2. пересобирается только он
  3. браузер получает update через WebSocket
  4. модуль заменяется без full reload

Узкая область обновления

Webpack часто инвалидировал большие части dependency graph.

Vite обновляет минимально необходимую область.

Это особенно важно на больших проектах.


HMR Graph

Vite поддерживает внутренний граф модулей:

Module A
 ├── Module B
 └── Module C

При изменении:

Module B

перезагружается только связанная часть дерева.


CSS в dev-режиме

CSS обрабатывается отдельно от JS.

Поддерживаются:

  • CSS Modules
  • PostCSS
  • Sass
  • Less
  • Stylus

CSS HMR

Изменение CSS:

body {
  background: black;
}

не приводит к reload страницы.

Vite обновляет стиль напрямую через <style> injection.


Обработка TypeScript

Vite не использует TypeScript compiler для transpilation.

Используется esbuild.


Что делает esbuild

Преобразование:

const id: number = 10

в:

const id = 10

Что esbuild не делает

Проверка типов отсутствует.

Для type checking используется:

tsc --noEmit

или:

vue-tsc

Архитектура production-сборки

Development-режим не подходит для production.

Причины:

  • слишком много HTTP-запросов
  • отсутствие оптимизации
  • отсутствие tree-shaking
  • отсутствие минификации

Поэтому Vite использует отдельный production pipeline.


Rollup как production engine

Production build выполняется через Rollup.

Команда:

vite build

запускает полноценную сборку.


Почему именно Rollup

Rollup хорошо подходит для production благодаря:

  • tree-shaking
  • chunk optimization
  • статическому анализу ESM
  • гибкой plugin architecture

Этапы production build

1. Построение dependency graph

Rollup анализирует:

import ...
export ...

2. Tree Shaking

Неиспользуемый код удаляется.

Пример:

export function used() {}
export function unused() {}

Если используется только:

used()

то unused() будет удалена.


Code Splitting

Vite автоматически создает chunks.

Например:

const page = await import('./admin.js')

превращается в отдельный chunk.


Dynamic Imports

Dynamic import:

import('./dashboard.js')

создает lazy-loaded bundle.

Это уменьшает initial load.


Минификация

Production build включает:

  • удаление комментариев
  • сжатие переменных
  • dead code elimination
  • compression optimizations

Обработка ассетов

Vite обрабатывает:

  • изображения
  • шрифты
  • SVG
  • media files

Маленькие файлы

Могут быть встроены как base64:

data:image/png;base64,...

Крупные файлы

Копируются в:

dist/assets

Хеширование файлов

Production build генерирует:

app.8d72f.js
style.1f53c.css

Хеш нужен для:

  • cache busting
  • долгого browser caching

Manifest Generation

Можно включить manifest:

export default defineConfig({
  build: {
    manifest: true
  }
})

Vite создаст:

manifest.json

Это важно для backend-интеграций.


Различие transform pipeline

Dev Pipeline

Ориентирован на:

  • скорость
  • минимальную задержку
  • быстрый HMR

Production Pipeline

Ориентирован на:

  • размер bundle
  • производительность
  • оптимизацию
  • кеширование

Почему Vite не использует Rollup в dev-режиме

Rollup требует:

  • построения полного graph
  • bundle generation
  • анализа зависимостей

Даже быстрый Rollup не может обеспечить мгновенный startup на крупных проектах.


Влияние архитектуры на DX

Двухрежимная система существенно улучшает developer experience.


Быстрый старт проекта

Запуск:

npm run dev

обычно занимает менее секунды.


Быстрый HMR

Изменения появляются практически мгновенно.


Масштабируемость

Разница особенно заметна на крупных codebase.

Проекты с тысячами модулей сохраняют высокую скорость разработки.


Роль esbuild и Rollup

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


esbuild

Используется для:

  • dev transforms
  • dependency optimization
  • extremely fast transpilation

Rollup

Используется для:

  • production bundling
  • tree shaking
  • optimized output

Схема архитектуры Vite

Development

Browser
   ↓
Vite Dev Server
   ↓
On-demand Transform
   ↓
ESM Response

Production

Source Code
   ↓
Rollup Build
   ↓
Chunk Optimization
   ↓
Minification
   ↓
dist/

Разделение конфигураций

Некоторые настройки применяются только к конкретному режиму.


Dev-only настройки

server: {
  port: 5173
}

Build-only настройки

build: {
  sourcemap: true
}

Переменные окружения и режимы

Vite поддерживает режимы:

vite --mode development
vite --mode production
vite --mode staging

Разные env-файлы

Поддерживаются:

.env
.env.local
.env.production
.env.development

Импорт env-переменных

Используется:

import.meta.env

Например:

const api = import.meta.env.VITE_API_URL

Почему архитектура Vite считается современной

Vite строится вокруг возможностей платформы:

  • native ESM
  • современного браузерного API
  • HTTP-based module loading

Вместо эмуляции модульной системы через bundler.


Ограничения двухрежимной архитектуры

Различия dev и production

Иногда код может работать по-разному.

Причины:

  • dev использует native ESM
  • production использует Rollup bundle

Специфика dynamic imports

Некоторые edge-case сценарии:

import(path)

могут вести себя иначе после bundling.


SSR и двухрежимная модель

Vite расширяет архитектуру и на SSR.

Существует:

  • SSR dev pipeline
  • SSR production build

Middleware Mode

Vite можно встроить в собственный сервер:

const vite = await createViteServer({
  server: {
    middlewareMode: true
  }
})

Это используется в:

  • custom SSR
  • fullstack frameworks
  • backend integrations

Роль плагинов в двух режимах

Плагины могут работать:

  • только в dev
  • только в build
  • в обоих режимах

Пример

export default function plugin() {
  return {
    transform(code, id) {
      return code
    }
  }
}

Различие hook lifecycle

Некоторые hooks вызываются:

  • только во время dev server
  • только при Rollup build

Внутренний механизм маршрутизации запросов

Во время dev Vite перехватывает запросы:

/src/main.js
/@vite/client
/node_modules/

Специальный клиент Vite

Vite автоматически внедряет:

/@vite/client

Этот клиент отвечает за:

  • HMR
  • WebSocket connection
  • module updates
  • overlay ошибок

Error Overlay

Ошибки отображаются прямо в браузере.

Например:

Unexpected token

Vite показывает:

  • stack trace
  • source location
  • module path

Source Maps

В dev source maps генерируются практически мгновенно.

Production source maps можно включить:

build: {
  sourcemap: true
}

Почему Vite особенно эффективен для SPA

Single Page Applications содержат:

  • большое количество модулей
  • интенсивный HMR
  • множество UI-компонентов

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


Эволюция frontend tooling

Архитектура Vite стала переходом:

от:

everything bundled always

к:

native modules in dev
optimized bundling in production

Именно это разделение стало ключевой причиной высокой скорости Vite по сравнению с традиционными bundler-системами.