Vite и Vue 3: плагин @vitejs/plugin-vue

Связка Vite и Vue 3 строится вокруг концепции ESM-first (native ES Modules) и разделения режимов разработки и сборки. В основе лежит то, что Vite не бандлит приложение в режиме dev, а отдает модули по требованию через dev-сервер, а сборка выполняется Rollup-подобным пайплайном в production.

Для Vue 3 ключевым элементом интеграции выступает официальный плагин @vitejs/plugin-vue, обеспечивающий:

  • компиляцию Single File Components (SFC)
  • поддержку HMR (Hot Module Replacement)
  • трансформацию <script setup>
  • обработку <style scoped>
  • интеграцию с Vue Compiler SFC

Без этого плагина Vite воспринимает .vue файлы как обычный текстовый импорт и не способен интерпретировать их структуру.


Роль @vitejs/plugin-vue в сборочном процессе

Плагин работает на уровне трансформации модулей Vite. Каждый .vue файл проходит через несколько стадий:

  1. Разбор SFC в AST (Abstract Syntax Tree)

  2. Разделение на блоки:

    • <template>
    • <script> / <script setup>
    • <style>
  3. Компиляция шаблона в render-функцию

  4. Преобразование script блока в ES module

  5. Инъекция HMR-метаданных

  6. Обработка CSS scoping и постобработка

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


Установка и базовая интеграция

Плагин подключается в конфигурации Vite через plugins:

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

export default defineConfig({
  plugins: [vue()]
})

На этом уровне Vite начинает распознавать .vue как полноценные модули и передает их в пайплайн плагина.

Дополнительно используется peer-зависимость vue/compiler-sfc, которая должна соответствовать версии Vue 3.


Обработка Single File Components

Разделение блоков SFC

Каждый Vue SFC разбивается на логические части:

  • Script block: логика компонента
  • Template block: декларативный UI
  • Style block: стили с поддержкой scoped и modules

Пример структуры:

<template>
  <div>{{ message }}</div>
</template>

<script setup>
const message = 'Hello'
</script>

<style scoped>
div {
  color: red;
}
</style>

Плагин превращает это в набор виртуальных импортов:

  • Component.vue?vue&type=template
  • Component.vue?vue&type=script
  • Component.vue?vue&type=style&index=0

Компиляция template в render-функции

Vue 3 использует компиляцию шаблонов в render-функции Jav * aScript:

import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

export function render(_ctx, _cache) {
  return (_openBlock(), _createElementBlock("div", null, _toDisplayString(_ctx.message)))
}

@vitejs/plugin-vue передает template в Vue compiler, который:

  • анализирует директивы (v-if, v-for)
  • оптимизирует static nodes
  • генерирует hoisted constants
  • создает block tree для patching

Оптимизация static hoisting особенно важна для производительности, так как снижает количество операций diff при рендеринге.


Поддержка <script setup>

Одним из ключевых элементов Vue 3 является script setup, который обрабатывается плагином на этапе трансформации.

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

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

Трансформация:

  • удаление boilerplate export default
  • автоматическое создание setup() функции
  • hoisting импортов
  • связывание реактивных переменных с template scope

Результат примерно эквивалентен:

export default {
  setup() {
    const count = ref(0)
    return { count }
  }
}

Но фактически используется более низкоуровневая оптимизация без явного объекта.


Scoped styles и CSS Modules

Scoped CSS

При использовании:

<style scoped>
.button {
  color: blue;
}
</style>

плагин:

  • генерирует уникальный атрибут (data-v-hash)
  • модифицирует селекторы
  • добавляет атрибут в template AST

Пример трансформации:

.button[data-v-123abc] {
  color: blue;
}

И в DOM:

<button data-v-123abc>Click</button>

CSS Modules

При использовании:

<style module>
.title {
  color: green;
}
</style>

плагин генерирует объект:

export default {
  title: '_title_1a2b3c'
}

И предоставляет его в компонент через $style.


Hot Module Replacement (HMR)

HMR в связке Vite + Vue 3 работает на уровне granular updates:

Типы обновлений:

  • Template update → перерисовка render-функции
  • Script update → пересоздание компонента
  • Style update → инжект CSS без перезагрузки
  • Props/state update → частичный re-render

Плагин отправляет HMR-сообщения через WebSocket:

import.meta.hot.accept()

Vue runtime получает обновление и заменяет только измененную часть компонента, сохраняя состояние, если это возможно.


Взаимодействие с системой модулей Vite

Vite строит dependency graph на основе ES imports:

import MyComponent from './MyComponent.vue'

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

  • main module
  • template module
  • style modules
  • script module

Это позволяет Vite:

  • выполнять tree-shaking
  • разделять чанки
  • оптимизировать lazy-loading

Оптимизация production сборки

В production режиме Vite использует Rollup-подобную сборку:

@vitejs/plugin-vue участвует в следующих этапах:

  • инлайнинг шаблонов
  • минификация render-функций
  • удаление dev-only кода
  • оптимизация CSS extraction

Особенно важна работа с static nodes:

<div>
  <h1>Static title</h1>
</div>

Такие узлы hoistятся и не пересоздаются при каждом рендере.


TypeScript интеграция

Плагин поддерживает TypeScript внутри <script lang="ts">:

<script setup lang="ts">
interface User {
  name: string
}

const user: User = { name: 'Alex' }
</script>

Обработка включает:

  • удаление типов на этапе трансформации
  • передача кода в esbuild или ts compiler
  • сохранение типовых деклараций для IDE

SSR (Server-Side Rendering) поддержка

При использовании SSR плагин обеспечивает:

  • генерацию server bundle
  • hydration mapping
  • согласование client/server templates

Основная задача — сохранить идентичность DOM между сервером и клиентом, используя одинаковые render-функции.


Работа с плагинами Vue внутри Vite

@vitejs/plugin-vue может быть расширен через дополнительные плагины:

  • macro plugins
  • JSX support (@vitejs/plugin-vue-jsx)
  • custom transform hooks

Пайплайн выглядит как цепочка:

  1. Vite module transform
  2. Vue SFC parse
  3. Vue template compile
  4. JS transform
  5. CSS transform
  6. Vite optimize step

Ограничения и особенности поведения

Некоторые важные нюансы:

  • .vue файлы всегда компилируются, даже при отсутствии template
  • HMR работает только при сохранении структуры SFC
  • изменения в compiler-sfc требуют перезапуска dev-сервера
  • scoped styles могут влиять на производительность при большом количестве компонентов

Роль плагина в современном frontend pipeline

@vitejs/plugin-vue фактически является мостом между декларативной моделью Vue SFC и ESM-ориентированной архитектурой Vite.

Он выполняет не просто трансформацию файлов, а полноценную реконструкцию компонентов в виде графа модулей, где каждая часть SFC становится независимым, оптимизируемым узлом сборки.

Это позволяет Vite сохранять минимальное время dev startup, а Vue 3 — поддерживать высокую реактивность и предсказуемость рендера без дополнительного runtime overhead.