Проблемы с SSR

Chakra UI — это современная библиотека компонентов для React, ориентированная на удобство разработки интерфейсов с поддержкой темы, адаптивности и доступности. Однако при интеграции с серверным рендерингом (SSR, Server-Side Rendering) возникают специфические проблемы, которые требуют тщательного понимания механизма работы Chakra UI и особенностей SSR.


Особенности SSR в Chakra UI

Chakra UI использует CSS-in-JS, что означает динамическую генерацию стилей на основе пропсов компонентов и текущей темы. При серверной отрисовке это создает два основных вызова:

  1. Генерация HTML на сервере — сервер создает готовый HTML с базовыми компонентами.
  2. Генерация CSS на клиенте — Chakra UI вставляет стили после гидратации, используя Emotion.

Основная проблема здесь заключается в том, что CSS, сгенерированный на сервере, должен совпадать с CSS на клиенте. Любое расхождение приведет к «мерцающим» стилям или предупреждениям React о несоответствии содержимого DOM.


Общие ошибки при SSR с Chakra UI

  1. Отсутствие ChakraProvider на сервере Если ChakraProvider не используется на этапе серверного рендеринга, компоненты Chakra не смогут получить текущую тему и стили. Это приведет к дефолтному отображению или некорректным стилям.

  2. Использование window или document на сервере Некоторые компоненты, например модальные окна или popover, зависят от размеров окна или портала в DOM. На сервере объектов window и document нет, что вызывает ошибки выполнения.

  3. Несинхронизированные стили при гидратации Эмоциональная библиотека (Emotion), используемая Chakra UI, генерирует уникальные классы CSS. Если порядок генерации отличается между сервером и клиентом, появляются mismatch warnings в React.


Практики корректного SSR с Chakra UI

Использование ChakraProvider с темой

На сервере и клиенте необходимо оборачивать приложение в один и тот же ChakraProvider:

import { ChakraProvider } from "@chakra-ui/react";
import theme from "./theme";

function App({ Component, pageProps }) {
  return (
    <ChakraProvider theme={theme}>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

export default App;

Для Next.js это обычно делается в _app.js или _app.tsx.


Генерация стилей на сервере

Chakra UI использует Emotion для CSS-in-JS, поэтому при SSR нужно извлекать стили, чтобы они попадали в HTML:

import { renderToString } from "react-dom/server";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";
import { ChakraProvider } from "@chakra-ui/react";
import theme from "./theme";

const cache = createCache({ key: "css" });

const html = renderToString(
  <CacheProvider value={cache}>
    <ChakraProvider theme={theme}>
      <App />
    </ChakraProvider>
  </CacheProvider>
);

const css = cache.sheet.tags.map(tag => tag.textContent).join("");

Эта техника позволяет вставлять CSS прямо в <head> HTML, предотвращая мерцание стилей.


Устранение зависимости от браузерного API

Компоненты, использующие порталы или измерения элементов, нужно рендерить только на клиенте. Chakra UI предоставляет useDisclosure и Portal, но для SSR важно проверять typeof window !== "undefined":

const isClient = typeof window !== "undefined";

return isClient ? <Modal isOpen={isOpen} onCl ose={onClose}>...</Modal> : null;

Такой подход предотвращает ошибки при серверной отрисовке.


Синхронизация цветовой схемы

Chakra UI поддерживает цветовую схему (colorMode). Если на сервере и клиенте она отличается, компонент может «мигнуть» при гидратации. Для согласованности используют:

  • ColorModeScript в Next.js _document.js:
import { ColorModeScript } from "@chakra-ui/react";
import theme from "./theme";

<Html>
  <Head />
  <body>
    <ColorModeScript initialColorMode={theme.config.initialColorMode} />
    <Main />
    <NextScript />
  </body>
</Html>

Это гарантирует, что начальная цветовая схема совпадает на сервере и клиенте.


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

  1. Минимизация рендеринга тяжелых компонентов на сервере — перенос интерактивных компонентов на клиент снижает нагрузку и предотвращает ошибки.
  2. Кэширование сгенерированного CSS — если страница генерируется часто, можно кэшировать результат Emotion, чтобы ускорить выдачу HTML.
  3. Избегание динамических значений в стилях на сервере — переменные, зависящие от времени или случайных чисел, создают рассогласование классов.

Итоговые рекомендации

  • Всегда использовать один и тот же ChakraProvider с темой на сервере и клиенте.
  • Вставлять ColorModeScript для согласования цветовой схемы.
  • Оборачивать приложение в CacheProvider Emotion для SSR-совместимости.
  • Избегать обращения к window, document и другим браузерным API на сервере.
  • Минимизировать динамический CSS и тяжелые интерактивные компоненты на сервере.

Соблюдение этих принципов позволяет Chakra UI корректно работать с серверным рендерингом, избегая расхождений стилей, ошибок гидратации и мерцания интерфейса.