Preact — библиотека интерфейсов с API, знакомым по React, но с компактным ядром и ставкой на производительность. В сентябре 2026 года вышла Preact 11: она сохранила привычные компоненты и хуки, добавила Hydration 2.0, автоматическую передачу ref и перешла на ESM. Для сайта, где важен размер бандла и скорость отрисовки, это практичная альтернатива тяжёлому фреймворку — если понимать отличия и не тащить compat без необходимости.

Что нового в Preact 11

Одиннадцатая версия — обновление с минимумом ломающих изменений после Preact X:

  • Hydration 2.0: асинхронные границы могут возвращать ноль или несколько DOM-узлов;
  • ref передаётся как обычный prop, forwardRef больше не нужен;
  • хуки сравнивают зависимости через Object.is, включая NaN;
  • createPortal доступен из ядра preact;
  • пакеты распространяются только как ESM с расширением .mjs;
  • в preact/compat появились use() и useEffectEvent();
  • SuspenseList удалён, а useRef в типах требует начальное значение.

Если проект на Preact 10, обновите TypeScript до 5.1 и проверьте сборку: CommonJS- и UMD-точки входа больше не поставляются. Обычно миграция сводится к правке импортов и типов.

Быстрый старт

Генератор create-preact поднимает проект на Vite и предлагает TypeScript, маршрутизацию через preact-iso и ESLint. Конфигурацию можно менять позже.

npm init preact
cd my-preact-app
npm install
npm run dev
npm run build

В разработке Vite отдаёт модули без минификации, а npm run build собирает оптимизированный dist/. Проверить production-сборку можно командой npm run preview. Не публикуйте dist без проверки путей, если приложение в подкаталоге.

Компоненты и хуки

Компонент — функция, принимающая props и возвращающая JSX. Хуки импортируются из preact/hooks, а не из react. Состояние обновляйте функцией, чтобы не терять предыдущее значение при быстрых кликах.

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

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

  useEffect(() => {
    document.title = `Счёт: ${count}`;
  }, [count]);

  return (
    <button onClick={() => setCount((c) => c + step)}>
      Счёт: {count}
    </button>
  );
}

Монтирование выполняет render из ядра. В Preact 11 аргумент replaceNode удалён, для замены части DOM используйте preact-root-fragment. В TypeScript настройте JSX на Preact, иначе редактор будет искать типы React.

import { render } from 'preact';
import { Counter } from './counter';

const root = document.getElementById('app');
if (root) render(<Counter step={2} />, root);
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact",
    "strict": true,
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "target": "ES2022"
  }
}

skipLibCheck полезен, когда сторонняя библиотека приносит типы React: Preact compat покрывает не всё, и без этого флага сборка может падать на чужих .d.ts. Но не отключайте strict — типы здесь помогают ловить ошибки в props и ref.

Signals

Signals хранят состояние вне компонента и обновляют только узлы, читающие значение. Это не замена хукам, а дополнение для часто меняющихся данных: счётчиков, фильтров, корзины.

import { signal, computed, effect } from '@preact/signals';

const count = signal(0);
const double = computed(() => count.value * 2);

effect(() => {
  console.log(double.value);
});

count.value++;

В компоненте достаточно прочитать count.value в JSX — подписка произойдёт автоматически. Для локального состояния есть useSignal и useComputed. Не превращайте все данные в глобальные сигналы: это усложняет тесты и жизненный цикл.

Совместимость с React

preact/compat позволяет использовать React-библиотеки: компоненты, хуки, порталы, lazy и Suspense. Vite-пресет подключает алиасы сам, в существующей сборке их пропишите вручную.

resolve: {
  alias: {
    react: 'preact/compat',
    'react-dom': 'preact/compat',
    'react-dom/test-utils': 'preact/test-utils',
    'react/jsx-runtime': 'preact/jsx-runtime'
  }
}

Compat не гарантирует побайтовую совместимость: библиотеки, которые лезут во внутренности React или полагаются на SuspenseList, могут не работать. В Preact 11 px для числовых style-значений и defaultProps перенесены в compat, а ref для классовых компонентов не передаётся — как в React. Проверяйте такие места тестами.

Маршрутизация и SSR

preact-iso — лёгкий роутер от команды Preact. Он поддерживает ленивую загрузку страниц и SSR. Для метаданных и кода ответа используйте его возможности, а не самодельные обходы.

import { LocationProvider, Router, Route } from 'preact-iso';
import { Home } from './pages/home';
import { Catalog } from './pages/catalog';

export function App() {
  return (
    <LocationProvider>
      <Router>
        <Route path="/" component={Home} />
        <Route path="/catalog" component={Catalog} />
      </Router>
    </LocationProvider>
  );
}

Для серверного рендеринга используйте preact-render-to-string, на клиенте — hydrate. В Preact 11 гидратация лучше работает с потоковым HTML и асинхронными границами, но разметка должна совпадать. Если сервер и клиент отдают разный HTML, гидратация будет нестабильной.

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

const html = renderToString(<App />);
console.log(html);

Сборка и производительность

Размер бандла — это время загрузки. После сборки посмотрите, сколько занимает JS и сколько из него приходится на compat. Если React-библиотеки не нужны, compat не подключайте: он добавляет код и компромиссы.

npm run build
du -h dist/assets/*.js
gzip -c dist/assets/index-*.js | wc -c
npm run preview

Делите код по маршрутам через lazy и динамические импорты, не грузите тяжёлые виджеты на первом экране, используйте preact/debug только в разработке. Для профилирования подойдут React DevTools. Следите за Core Web Vitals, а не только за размером файла: длинный main-thread портит впечатление даже при маленьком бандле.

Тесты и качество

Для тестов хватает Vitest и @testing-library/preact. Проверяйте поведение, а не внутреннюю структуру компонентов: так тесты переживут рефакторинг и переход на сигналы.

npm i -D vitest jsdom @testing-library/preact
npx vitest run
npm run build

В тестах проверяйте доступность: роль кнопки, подпись поля, порядок фокуса. Preact не навязывает разметку, семантика остаётся ответственностью разработчика. dangerouslySetInnerHTML используйте только после санитизации: библиотека экранирует значения по умолчанию, но не отменяет правила безопасности.

Итог

Preact 11 — практичный выбор для интерфейсов, где важны размер, скорость и знакомый API. Он даёт хуки, сигналы, SSR, роутер и совместимость с React-экосистемой, но требует дисциплины: не подключать compat без нужды, следить за типами и проверять поведение сторонних библиотек. Начните с npm init preact, соберите маленький экран на хуках, затем добавьте сигналы и измерьте бандл. Если после этого приложение остаётся быстрым и понятным, вы получили именно то, за чем идут к Preact — лёгкий интерфейс без лишнего веса.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте