Vite и Preact

Связка Vite и Preact строится вокруг минимального runtime и максимально быстрого dev-сервера. Vite предоставляет ESM-ориентированную систему сборки, где код модулей загружается напрямую через браузер в режиме разработки, а Preact обеспечивает компактную реализацию React-совместимого API с акцентом на скорость и малый размер бандла.

Ключевая особенность взаимодействия — использование плагина @preact/preset-vite, который автоматически заменяет React на Preact через алиасы и подключает оптимизированный JSX-трансформер.


Базовая структура проекта

Типичная структура проекта с Vite и Preact выглядит следующим образом:

src/
  components/
  hooks/
  app.jsx
  main.jsx
index.html
vite.config.js
package.json

Точка входа задаётся в main.jsx, где выполняется монтирование корневого компонента.

import { render } from "preact";
import { App } from "./app";

render(<App />, document.getElementById("root"));

Vite автоматически связывает index.html как часть графа зависимостей, что делает HTML полноценным участником сборочного процесса.


Установка и конфигурация Vite с Preact

Интеграция базируется на плагине:

npm create vite@latest my-app
cd my-app
npm install
npm install preact
npm install -D @preact/preset-vite

Конфигурация vite.config.js:

import { defineConfig } from "vite";
import preact from "@preact/preset-vite";

export default defineConfig({
  plugins: [preact()]
});

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

  • подмена react и react-dom на preact/compat
  • настройка JSX трансформации
  • оптимизация Fast Refresh
  • подключение dev-time оптимизаций

JSX трансформация и compat-слой

Preact использует совместимый слой preact/compat, который эмулирует API React. Это позволяет использовать привычные конструкции:

import { useState } from "preact/hooks";

export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onCl ick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

Vite через плагин автоматически настраивает JSX runtime, поэтому ручная настройка jsxImportSource часто не требуется.

Внутри работает оптимизированный JSX-преобразователь, который минимизирует количество промежуточных вызовов и уменьшает runtime overhead.


Dev-сервер Vite и поведение HMR

Dev-сервер Vite работает поверх native ESM:

  • каждый модуль запрашивается браузером отдельно
  • трансформация выполняется on-demand
  • кеширование осуществляется на уровне HTTP-заголовков

При изменении Preact-компонента активируется Fast Refresh через HMR API.

Основные особенности HMR в связке:

  • сохранение состояния компонентов при обновлении
  • точечное обновление дерева компонентов
  • минимизация перерисовки DOM

Preact Fast Refresh интегрирован через плагин, обеспечивая совместимость с функциональными компонентами и хуками.


Оптимизация бандла

Vite выполняет продакшн-сборку через Rollup, что обеспечивает tree-shaking и код-сплиттинг.

Preact дополнительно уменьшает размер бандла за счёт:

  • отсутствия виртуал-диффа React-уровня сложности
  • компактной реализации JSX runtime
  • возможности исключения compat слоя при отсутствии зависимости от React API

Пример результата сборки:

  • React + ReactDOM: ~40–50 KB (minified + gzip)
  • Preact: ~4 KB (core)
  • Preact + compat: ~10 KB

Плагины и расширение функциональности

Основной инструмент интеграции:

@preact/preset-vite

Функциональность:

  • автоматический alias React → Preact
  • настройка JSX runtime
  • включение Fast Refresh
  • оптимизация dev warnings

Конфигурация с дополнительными опциями:

import { defineConfig } from "vite";
import preact from "@preact/preset-vite";

export default defineConfig({
  plugins: [
    preact({
      reactAliasesEnabled: true,
      include: [/\.jsx$/, /\.tsx$/]
    })
  ]
});

Работа с хуками и состоянием

Preact hooks совместимы с React Hooks API, но имеют более лёгкую реализацию.

useState и useEffect

import { useState, useEffect } from "preact/hooks";

export function Timer() {
  const [time, setTime] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setTime(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);

  return <div>{time}</div>;
}

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

  • отсутствие тяжелой reconciliation логики
  • минимальный overhead на подписки эффектов
  • быстрый lifecycle execution

Signals в Preact

Современная архитектура Preact включает сигналы как альтернативу классическим хукам состояния.

import { signal } from "@preact/signals";

const count = signal(0);

export function Counter() {
  return (
    <button onCl ick={() => count.value++}>
      {count.value}
    </button>
  );
}

Сигналы обеспечивают:

  • точечное обновление DOM без rerender всего компонента
  • реактивность на уровне значений
  • минимальную зависимость от reconciliation

Vite не требует дополнительной настройки для signals, так как они работают на уровне runtime.


Alias React → Preact и совместимость библиотек

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

Через alias:

resolve: {
  alias: {
    react: "preact/compat",
    "react-dom": "preact/compat"
  }
}

Это позволяет подключать:

  • UI-библиотеки React
  • хуки сторонних разработчиков
  • компоненты без изменений

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

  • некоторые React-специфичные API могут работать частично
  • Concurrent Mode не поддерживается полностью
  • некоторые devtools-расширения требуют адаптации

SSR в связке Vite и Preact

Vite поддерживает SSR через отдельный серверный билд.

Пример серверного рендера:

import { h } from "preact";
import renderToString from "preact-render-to-string";
import { App } from "./app";

export function render() {
  return renderToString(<App />);
}

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

  • минимальный hydration payload
  • быстрый time-to-first-byte
  • совместимость с Vite middleware mode

Code splitting и динамические импорты

Vite использует нативный dynamic import:

const LazyComponent = () => import("./components/Lazy");

В Preact это работает без дополнительных адаптаций.

Для компонентной ленивой загрузки:

import { lazy, Suspense } from "preact/compat";

const Heavy = lazy(() => import("./Heavy"));

export function App() {
  return (
    <Suspense fallback={<div>loading</div>}>
      <Heavy />
    </Suspense>
  );
}

Производительность и поведение runtime

Комбинация Vite + Preact характеризуется следующими параметрами:

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

Причина эффективности:

  • отсутствие bundling в dev-режиме
  • ESM-first архитектура Vite
  • упрощённый VDOM Preact

Типичные сценарии использования

Архитектура часто применяется в:

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

Особенности интеграции с TypeScript

TypeScript поддерживается без дополнительной конфигурации, кроме базового tsconfig.json.

Типичная настройка JSX:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}

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


Поведение при production build

Сборка через Vite:

  • Rollup формирует оптимизированные чанки
  • CSS извлекается отдельно
  • tree-shaking удаляет неиспользуемые части Preact
  • compat-слой может быть исключён при отсутствии React-зависимостей

Результат — минимальный runtime с предсказуемой загрузкой ресурсов и стабильной производительностью в браузере.