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

Архитектура окружений в Vite основана на разделении контекста выполнения на независимые среды, каждая из которых обладает собственным графом модулей, конфигурацией трансформации и стратегией бандлинга. Пользовательское окружение в этой модели представляет собой расширяемую сущность, позволяющую вводить дополнительные изолированные контексты помимо стандартных client и server, которые применяются в классическом SSR или SPA сценариях.

Каждое окружение в Vite представляет собой самостоятельный слой обработки модулей, включающий:

  • собственный граф зависимостей
  • набор плагинов или их подмножество
  • стратегию резолва импортов
  • правила трансформации кода
  • систему кэширования

Ключевая идея заключается в том, что один проект может одновременно обслуживать несколько целевых платформ или рантаймов без смешивания их логики. Это особенно важно в сценариях SSR, edge runtime и гибридных приложениях.

Пользовательское окружение расширяет эту модель, позволяя вводить новые типы исполнения кода, например:

  • edge-окружения (Cloudflare Workers, Deno Deploy)
  • serverless-функции
  • изолированные worker-контексты
  • специализированные build-time окружения

Базовая концепция пользовательского окружения

Пользовательское окружение в Vite определяется как объект конфигурации, описывающий:

  • имя окружения
  • стратегию выполнения модулей
  • плагины и их поведение
  • условия трансформации
  • правила внешних зависимостей

Логически окружение выступает как контейнер, в котором Vite строит отдельный pipeline обработки модулей.

Внутри архитектуры Vite окружение не является просто набором настроек, а полноценным runtime-контекстом, который может иметь собственный dev-server pipeline и собственный build pipeline.

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

Современная архитектура Vite (начиная с концепции Environments API) вводит возможность декларативного описания окружений через конфигурацию:

export default {
  environments: {
    edge: {
      dev: {
        optimizeDeps: {
          include: ['lodash-es']
        }
      },
      build: {
        target: 'es2022'
      }
    }
  }
}

В этом примере создаётся дополнительное окружение edge, которое существует параллельно с основными клиентскими и серверными контекстами.

Каждое окружение может иметь собственные параметры:

  • dev — поведение в режиме разработки
  • build — параметры сборки
  • resolve — стратегия поиска модулей
  • plugins — отдельный стек плагинов

Расширение окружений через плагины

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

Пример логики:

  • клиентское окружение обрабатывает React/Vue компоненты
  • серверное окружение транспилирует Node.js-специфичный код
  • edge окружение ограничивает использование Node API

Плагин может проверять текущий контекст выполнения:

export function myPlugin() {
  return {
    name: 'env-aware-plugin',
    transform(code, id, options) {
      if (options.environment?.name === 'edge') {
        // упрощённая трансформация для edge runtime
      }
    }
  }
}

Таким образом, один и тот же плагин может адаптировать поведение в зависимости от окружения.

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

Каждое окружение строит собственный module graph. Это означает:

  • импорт одного и того же модуля может быть обработан по-разному
  • кеширование изолировано
  • HMR работает в рамках конкретного окружения

При этом Vite синхронизирует зависимости между окружениями только на уровне исходных файлов, но не на уровне трансформированного результата.

Такой подход позволяет, например, использовать общий исходный код, но генерировать разные артефакты для browser и server runtime.

Разделение dev и build pipeline

Пользовательское окружение всегда разделяет два ключевых режима:

Dev pipeline

В режиме разработки окружение:

  • работает через middleware dev server
  • использует lazy трансформации
  • поддерживает HMR в пределах контекста
  • оптимизирует только используемые зависимости

Build pipeline

В режиме сборки:

  • формирует статический бандл
  • применяет tree-shaking на уровне окружения
  • может генерировать отдельные output директории
  • поддерживает разные target-версии ECMAScript

Каждое окружение может иметь собственную стратегию сборки, что особенно важно для multi-runtime приложений.

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

Несмотря на изоляцию, окружения могут взаимодействовать через:

  • общий исходный код
  • shared dependencies
  • виртуальные модули
  • explicit bridging APIs

Пример сценария:

  • client окружение рендерит UI
  • server окружение выполняет SSR
  • edge окружение обрабатывает API middleware

При этом один и тот же модуль может быть импортирован в разные окружения, но с разной интерпретацией.

Конфигурация внешних зависимостей

В пользовательских окружениях важную роль играет управление external-зависимостями.

Каждое окружение может иметь:

  • собственный список external пакетов
  • различную стратегию bundling
  • ограничения на Node built-ins

Пример:

environments: {
  edge: {
    ssr: {
      external: ['fs', 'path']
    }
  }
}

Такой подход предотвращает попадание несовместимых модулей в runtime, где они не поддерживаются.

Оптимизация зависимостей на уровне окружений

Vite выполняет pre-bundling зависимостей отдельно для каждого окружения. Это означает:

  • оптимизация кеша происходит изолированно
  • разные окружения могут использовать разные версии одной библиотеки
  • ускорение dev server достигается за счёт локального анализа графа

Особенно это важно при работе с monorepo, где один пакет может обслуживать несколько runtime-целей.

Использование виртуальных окружений

Пользовательское окружение может быть реализовано как виртуальный слой, не привязанный к физическому runtime. В этом случае оно используется для:

  • генерации промежуточного кода
  • анализа зависимостей
  • статической трансформации
  • подготовки метаданных для других окружений

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

Типовые сценарии применения

Пользовательские окружения наиболее эффективно используются в следующих архитектурах:

  • SSR приложения с отдельным server и client контекстами
  • Edge-first приложения с распределённым выполнением логики
  • платформы с несколькими target runtime одновременно
  • дизайн-системы с разными режимами сборки компонентов
  • monorepo архитектуры с изолированными пакетами исполнения

Каждый из этих сценариев требует строгой изоляции графов модулей и гибкой конфигурации пайплайна трансформации.

Ограничения и архитектурные особенности

Модель пользовательских окружений накладывает ряд ограничений:

  • невозможность прямого разделения runtime state между окружениями
  • необходимость явного описания external зависимостей
  • усложнение конфигурации плагинов
  • рост стоимости анализа графа при большом числе окружений

При этом архитектура остаётся предсказуемой за счёт строгого разделения контекстов и детерминированного построения графов.

Роль пользовательских окружений в масштабируемой архитектуре

Пользовательские окружения формируют основу для перехода от монолитного dev-server к многослойной системе сборки. Это позволяет рассматривать Vite не только как инструмент разработки, но как инфраструктурный слой для управления кодом в разных рантаймах.

Изоляция окружений обеспечивает:

  • предсказуемость сборки
  • уменьшение конфликтов зависимостей
  • возможность расширения под новые runtime-платформы
  • гибкость в построении сложных приложений с распределённой логикой