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

Naive UI — это современная Vue 3-библиотека компонентов, ориентированная на легкость кастомизации и полный контроль над стилями. При работе с серверным рендерингом (SSR, Server-Side Rendering) её использование требует внимательного подхода, так как многие UI-компоненты изначально рассчитывают на работу в браузерной среде.

Рендеринг компонентов на сервере

При SSR компоненты Naive UI должны корректно обрабатывать отсутствие объектов, специфичных для браузера, таких как window, document или navigator. Некоторые встроенные элементы библиотеки (например, n-popover, n-tooltip, n-dialog) используют динамическое позиционирование, основанное на DOM, и их рендеринг на сервере может привести к ошибкам.

Рекомендации:

  • Использовать условный рендеринг с v-if="process.client" или аналогичными проверками для элементов, зависящих от DOM.
  • Компоненты, поддерживающие SSR, обычно корректно рендерятся как статические контейнеры на сервере, а их интерактивность активируется на клиенте.

Стиль и CSS при SSR

Naive UI применяет CSS-in-JS подход, который позволяет динамически генерировать стили компонентов. При SSR важно учитывать:

  • Для корректного внедрения стилей на сервере необходимо подключить createTheme и provideTheme на уровне приложения.
  • Использование useTheme внутри компонента на сервере должно выполняться с правильным контекстом, иначе могут появляться предупреждения о несовпадении идентификаторов стилей.

Пример инициализации темы для SSR:

import { createApp } from 'vue'
import { createSSRApp } from 'vue'
import { createTheme, NConfigProvider } from 'naive-ui'

const theme = createTheme({
  common: {
    primaryColor: '#42b983',
  }
})

const app = createSSRApp({
  setup() {
    return () => h(NConfigProvider, { theme }, [h(App)])
  }
})

Интерактивные элементы и жизненный цикл

Компоненты с динамическим поведением, такими как n-dropdown или n-calendar, создают DOM-элементы и слушатели событий только после монтирования на клиенте. На сервере они рендерятся в виде статических контейнеров.

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

  • Использовать onMounted для инициализации обработчиков событий.
  • Для компонентов с порталом (n-modal, n-popover) указывать контейнер рендеринга через teleport и проверять наличие document на сервере.

Пример условного использования портала:

<template>
  <n-popover v-if="mounted" :to="container">
    <template #trigger>
      <button>Открыть</button>
    </template>
    <div>Содержимое Popover</div>
  </n-popover>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const mounted = ref(false)
let container

onMounted(() => {
  container = document.body
  mounted.value = true
})
</script>

Гидратация и синхронизация состояния

При SSR важна корректная гидратация на клиенте. Несовпадение структуры DOM между сервером и клиентом может вызвать предупреждения hydration mismatch.

  • Компоненты Naive UI обычно безопасны при гидратации, если их состояние и контент не зависят от данных, доступных только на клиенте.
  • Для динамических данных, которые зависят от window или сторонних API, необходимо использовать v-if или отдельный клиентский рендеринг (client-only).

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

Naive UI оптимизирован для быстрого рендеринга, но при SSR нужно учитывать:

  • Большое количество интерактивных компонентов на странице увеличивает объем передаваемого HTML и время гидратации.
  • Стили, генерируемые на сервере, следует кэшировать или использовать pre-rendering для статических страниц.
  • Минимизация использования глобальных слотов и глубоких вложенных порталов снижает нагрузку на сервер.

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

  1. Проверять использование объектов браузера и оборачивать их проверками process.client.
  2. Для компонентов с динамическим поведением использовать отложенную инициализацию через onMounted.
  3. Обеспечивать корректную генерацию и подключение стилей через NConfigProvider и createTheme.
  4. Минимизировать количество компонентов с порталом и динамическими слоты, если страница рендерится на сервере.
  5. Использовать условный рендеринг для элементов, зависящих от клиентской среды, чтобы избежать mismatch при гидратации.

Этот подход обеспечивает стабильный SSR с Naive UI, предотвращает ошибки на сервере и сохраняет плавное клиентское взаимодействие.