Независимые развертывания

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

Архитектура Preact основана на виртуальном DOM (VDOM). Виртуальный DOM представляет собой легковесную копию реального DOM, позволяя эффективно обновлять только изменившиеся элементы интерфейса. Система рендеринга Preact использует diffing-алгоритм, который сравнивает предыдущую и текущую виртуальную структуру, минимизируя количество операций с реальным DOM.

Компоненты и их жизненный цикл

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

Функциональный компонент создаётся как обычная JavaScript-функция, возвращающая JSX:

import { h } from 'preact';

function Button({ label, onClick }) {
  return <button onCl ick={onClick}>{label}</button>;
}

Классовый компонент наследует Component из Preact и предоставляет методы жизненного цикла:

  • componentDidMount — вызывается после первого рендера компонента.
  • componentDidUpdate — вызывается после обновления компонента.
  • componentWillUnmount — выполняется перед удалением компонента.

Хуки и управление состоянием

Preact поддерживает популярные хуки, аналогичные React, такие как useState, useEffect, useRef и useContext.

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

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

  useEffect(() => {
    const timer = setInterval(() => setCount(prev => prev + 1), 1000);
    return () => clearInterval(timer);
  }, []);

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

Ключевые моменты использования хуков:

  • useState позволяет хранить локальное состояние компонента.
  • useEffect используется для побочных эффектов: подписки, таймеры, сетевые запросы.
  • Хуки всегда должны вызываться на верхнем уровне компонента для правильной работы механизма рендеринга.

JSX и виртуальный DOM

JSX в Preact почти идентичен React, но компилируется в функцию h(), предоставляемую Preact. Каждый JSX-элемент превращается в виртуальный DOM-объект:

<h1 class="title">Привет, Preact</h1>

Компилируется в:

h('h1', { class: 'title' }, 'Привет, Preact')

Эта трансформация позволяет Preact эффективно работать с виртуальным DOM и минимизировать количество операций с реальным DOM.

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

Preact имеет встроенные механизмы оптимизации:

  • Минимальный размер библиотеки — ~3 кБ после gzip.
  • Быстрый diffing — обновляются только изменившиеся узлы.
  • Ленивый рендеринг — можно использовать динамический импорт для компонентов (preact-async-route).
  • Мемоизация компонентов через memo для предотвращения ненужных перерендеров:
import { h } from 'preact';
import { memo } from 'preact/compat';

const ExpensiveComponent = memo(({ data }) => {
  return <div>{data}</div>;
});

Независимые развертывания

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

Подходы к независимым развертываниям:

  1. Web Components на основе Preact Preact позволяет создавать кастомные элементы, которые могут использоваться в любой среде:
import { h, render, Component } from 'preact';

class MyWidget extends Component {
  render() {
    return <div>Виджет Preact</div>;
  }
}

customElements.define('my-widget', class extends HTMLElement {
  connectedCallback() {
    render(<MyWidget />, this);
  }
});
  1. Микрофронтенды Компоненты Preact можно загружать динамически через import() и интегрировать с другими микрофронтендами:
async function loadComponent() {
  const { default: RemoteButton } = await import('./RemoteButton.js');
  render(<RemoteButton />, document.getElementById('button-container'));
}
  1. Self-contained bundles Каждый компонент может быть собран отдельным Webpack/ESBuild-бандлом с минимальными зависимостями. Использование preact/compat обеспечивает совместимость с существующими библиотеками React, позволяя компоненты интегрировать в старые проекты без полной миграции.

Управление состоянием в независимых модулях

Для изоляции состояния можно использовать:

  • Локальный state через useState.
  • Локальный context через createContext и useContext.
  • Event-driven подход с использованием кастомных событий DOM для обмена данными между модулями.
const MyContext = createContext();

function Provider({ children }) {
  const [value, setValue] = useState(0);
  return <MyContext.Provider value={{ value, setValue }}>{children}</MyContext.Provider>;
}

function Consumer() {
  const { value } = useContext(MyContext);
  return <div>{value}</div>;
}

Совместимость и интеграция

Preact можно легко интегрировать в существующие проекты, даже если они используют React, благодаря preact/compat. Это позволяет:

  • Использовать сторонние React-библиотеки.
  • Постепенно заменять React-компоненты на Preact.
  • Создавать гибридные приложения с микрофронтендами, где Preact-компоненты работают параллельно с React-компонентами.

Подходы к сборке и деплою

Для развертывания Preact-приложений и независимых модулей рекомендуется:

  • Использовать ESBuild или Vite для создания минимальных и быстрых бандлов.
  • Подключать модули через динамические импорты для снижения времени загрузки.
  • Поддерживать отдельные точки монтирования в DOM, чтобы каждый модуль можно было подключать независимо.

Такой подход обеспечивает гибкость, масштабируемость и высокую производительность больших приложений с множеством автономных компонентов.