Интеграция с CMS системами

Preact является лёгкой альтернативой React, что делает его удобным для интеграции с различными CMS-системами, такими как WordPress, Strapi, Sanity или Contentful. Основная цель интеграции — возможность динамически получать контент из CMS и рендерить его на клиентской стороне с использованием компонентов Preact.

Получение данных из CMS

Для взаимодействия с CMS чаще всего используется REST API или GraphQL. В Preact рекомендуется использовать хуки и асинхронные функции для получения данных. Пример работы с REST API:

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

function CMSContent({ endpoint }) {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        async function fetchData() {
            try {
                const response = await fetch(endpoint);
                const result = await response.json();
                setData(result);
            } catch (error) {
                console.error("Ошибка при загрузке данных:", error);
            } finally {
                setLoading(false);
            }
        }
        fetchData();
    }, [endpoint]);

    if (loading) return <p>Загрузка...</p>;
    if (!data) return <p>Нет данных для отображения</p>;

    return (
        <div>
            {data.items.map(item => (
                <article key={item.id}>
                    <h2>{item.title}</h2>
                    <p>{item.content}</p>
                </article>
            ))}
        </div>
    );
}

Ключевые моменты:

  • useEffect обеспечивает загрузку данных после монтирования компонента.
  • Асинхронная функция внутри useEffect позволяет корректно обрабатывать ошибки и состояние загрузки.
  • Рендеринг условных состояний (loading, data) предотвращает ошибки при отсутствии данных.

Работа с GraphQL

GraphQL упрощает выборку только нужных полей из CMS. Использование GraphQL в Preact аналогично React, с помощью fetch или библиотек вроде urql или Apollo Client.

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

const query = `
  query {
    posts {
      id
      title
      content
    }
  }
`;

function GraphQLContent({ endpoint }) {
    const [posts, setPosts] = useState([]);

    useEffect(() => {
        async function fetchGraphQL() {
            const response = await fetch(endpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ query })
            });
            const { data } = await response.json();
            setPosts(data.posts);
        }
        fetchGraphQL();
    }, [endpoint]);

    return (
        <div>
            {posts.map(post => (
                <article key={post.id}>
                    <h2>{post.title}</h2>
                    <p>{post.content}</p>
                </article>
            ))}
        </div>
    );
}

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

  • GraphQL позволяет минимизировать трафик, запрашивая только необходимые поля.
  • Лёгкая интеграция с Preact без специальных адаптеров.

Интеграция с WordPress

Для интеграции с WordPress используется REST API /wp-json/wp/v2/posts. Поскольку Preact отличается лёгкостью, компонент, отображающий посты, будет минимальным и производительным.

function WordPressPosts() {
    const [posts, setPosts] = useState([]);

    useEffect(() => {
        async function loadPosts() {
            const res = await fetch('https://example.com/wp-json/wp/v2/posts');
            const data = await res.json();
            setPosts(data);
        }
        loadPosts();
    }, []);

    return (
        <ul>
            {posts.map(post => (
                <li key={post.id}>
                    <h3 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
                    <div dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }} />
                </li>
            ))}
        </ul>
    );
}

Замечания:

  • Использование dangerouslySetInnerHTML необходимо для корректного отображения HTML-контента из WordPress.
  • Preact оптимизирует рендеринг, даже если количество постов велико.

Статическая генерация и Preact

Для CMS с поддержкой статических сайтов (например, Strapi или Contentful) Preact может использоваться совместно с Vite или Astro. Контент забирается на этапе сборки и рендерится как статические компоненты, что снижает нагрузку на клиент.

// Пример использования Astro + Preact
---
import CMSContent from '../components/CMSContent.jsx';

const posts = await fetch('https://cms.example.com/posts').then(res => res.json());
---

<CMSContent posts={posts} />

Преимущества:

  • Быстрый рендеринг страниц.
  • Меньше запросов к CMS на клиенте.
  • Возможность комбинировать динамические и статические данные.

Кеширование и оптимизация

Интеграция с CMS требует оптимизации загрузки данных:

  • Использовать SWR или аналогичные хуки для кеширования.
  • Минимизировать количество запросов через GraphQL.
  • Поддерживать инкрементальный рендеринг для больших списков контента.

Управление состоянием

При динамическом контенте состояние может быть централизованным через preact/signals или unistore. Это упрощает синхронизацию данных с компонентами.

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

export const postsSignal = signal([]);

export async function fetchPosts(endpoint) {
    const res = await fetch(endpoint);
    const data = await res.json();
    postsSignal.value = data;
}

Компоненты могут подписываться на postsSignal и автоматически обновляться при изменении данных.

Особенности безопасности

При работе с CMS важно учитывать:

  • Очистку входного HTML, если используется dangerouslySetInnerHTML.
  • Ограничение публичного API ключей, если CMS требует авторизации.
  • Обновление компонентов Preact при изменении структуры данных CMS.

Итоги архитектурного подхода

Интеграция Preact с CMS строится на:

  • Асинхронной загрузке данных через REST или GraphQL.
  • Разделении компонентов на презентационные и контейнерные.
  • Возможности статической генерации для ускорения страниц.
  • Централизованном управлении состоянием через сигналы или сторонние хранилища.

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