Розробка гібридного рендерингу (SSR + CSR) для веб-застосунку

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка гібридного рендерингу (SSR + CSR) для веб-застосунку
Складна
~5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка гібридного рендеру (SSR + CSR) для веб-застосунку

Гібридний рендер — коли різні частини застосунку або різні маршрути використовують різні стратегії рендеру в залежності від вимог. Публічні сторінки з SEO рендеряться на сервері, закриті дашборди — на клієнті, лендинги — статично. Все це в межах одного застосунку.

Це не компроміс «взяли чуть-чуть від кожного» — це точна архітектурна настройка під вимоги кожної частини продукту.

Моделі гібридного рендеру

За маршрутами (route-level rendering): кожний маршрут оголошує свою стратегію. Next.js, Nuxt 3 та SvelteKit підтримують це нативно.

За компонентами (component-level rendering): Server Components рендеряться на сервері, Client Components — на клієнті. Межа проходить всередині одного маршруту.

За сегментами (segment-level rendering): заголовок та навігація — статика, основний контент — SSR, віджети (чат, сповіщення) — CSR.

Конфігурація в Next.js App Router

// next.config.ts — routeRules / export config
export const revalidate = 3600; // За замовчуванням: ISR з TTL 1 година

Кожний сегмент маршруту управляє рендером незалежно:

app/
  (marketing)/          # Група без впливу layout
    page.tsx            # SSG — статична головна
    about/page.tsx      # SSG
    blog/
      page.tsx          # ISR — список постів
      [slug]/page.tsx   # ISR — пост
  (app)/
    layout.tsx          # Серверний layout з перевіркою сесії
    dashboard/
      page.tsx          # SSR — дашборд з реальними даними
    reports/
      page.tsx          # CSR — важкі графіки, тільки клієнт
// app/(app)/reports/page.tsx — примусовий CSR
'use client'; // Весь маршрут як клієнтський компонент

import dynamic from 'next/dynamic';

// Важкі бібліотеки тільки на клієнті
const RechartsChart = dynamic(() => import('@/components/charts/RechartsChart'), {
  ssr: false,
  loading: () => <ChartSkeleton />,
});

Конфігурація в Nuxt 3

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Публічний сайт
    '/': { prerender: true },
    '/about': { prerender: true },
    '/blog/**': { isr: 3600 },

    // API та застосунок
    '/api/**': { cors: true },
    '/app/**': { ssr: false },      // SPA для закритих розділів
    '/admin/**': { ssr: true },     // SSR для admin-панелі (SEO не потрібен, але швидка перша загрузка)
  },
});

Server та Client Components — межа рендеру

React Server Components (Next.js App Router) — ключ до гібридності на рівні компонентів:

// Серверний компонент — запит прямо до БД, без API-round-trip
// app/products/page.tsx
import { db } from '@/lib/db';
import { ProductCard } from './product-card'; // Серверний
import { FilterBar } from './filter-bar';     // Клієнтський

export default async function ProductsPage({
  searchParams
}: {
  searchParams: { category?: string; sort?: string }
}) {
  // Цей код виконується тільки на сервері
  const products = await db.product.findMany({
    where: { category: searchParams.category },
    orderBy: { [searchParams.sort ?? 'name']: 'asc' },
    include: { images: { take: 1 } },
  });

  return (
    <div>
      {/* Клієнтський компонент — управляє фільтрами через URL */}
      <FilterBar initialCategory={searchParams.category} />

      {/* Серверний компонент — просто рендерить дані */}
      <div className="grid grid-cols-3 gap-4">
        {products.map(product => (
          <ProductCard key={product.id} product={product} />
        ))}
      </div>
    </div>
  );
}
// filter-bar.tsx — клієнтський компонент
'use client';
import { useRouter, useSearchParams } from 'next/navigation';

export function FilterBar({ initialCategory }: { initialCategory?: string }) {
  const router = useRouter();
  const params = useSearchParams();

  function setCategory(category: string) {
    const newParams = new URLSearchParams(params);
    newParams.set('category', category);
    router.push(`?${newParams.toString()}`);
  }

  return (
    <nav>
      {CATEGORIES.map(cat => (
        <button key={cat.id} onClick={() => setCategory(cat.id)}>
          {cat.name}
        </button>
      ))}
    </nav>
  );
}

Передача даних між Server та Client компонентами

Server Components не можуть приймати функції від Client Components — тільки сериалізовані дані:

// Правильно: серверні дані як пропси клієнтського компонента
export default async function Page() {
  const user = await getUser(); // Серверний fetch
  return <UserProfile user={user} />; // user — сериалізовний об'єкт
}

// Неправильно: не можна передати функцію з Server у Client
// return <Button onClick={serverFunction} /> // Помилка компіляції

Для серверних дій (мутацій) використовуйте Server Actions:

// actions.ts
'use server';
import { revalidatePath } from 'next/cache';

export async function updateProduct(id: string, data: Partial<Product>) {
  await db.product.update({ where: { id }, data });
  revalidatePath(`/products/${id}`); // Інвалідувати кеш
}

// Клієнтський компонент викликає серверний екшен прямо
'use client';
import { updateProduct } from './actions';

function EditForm({ product }: { product: Product }) {
  return (
    <form action={async (formData) => {
      'use server'; // Вбудований серверний екшен
      await updateProduct(product.id, {
        name: formData.get('name') as string,
      });
    }}>
      <input name="name" defaultValue={product.name} />
      <button type="submit">Зберегти</button>
    </form>
  );
}

Стриміг та Suspense у гібридній архітектурі

// Паралельна загрузка незалежних серверних даних
import { Suspense } from 'react';

export default function DashboardPage() {
  return (
    <div>
      {/* Рендерится миттєво — не чекає даних */}
      <DashboardHeader />

      {/* Кожний блок стримується незалежно */}
      <Suspense fallback={<StatsSkeleton />}>
        <Stats />  {/* async компонент з fetch */}
      </Suspense>

      <Suspense fallback={<ChartSkeleton />}>
        <RevenueChart />
      </Suspense>

      <Suspense fallback={<TableSkeleton />}>
        <RecentOrders />
      </Suspense>
    </div>
  );
}

Користувач видить заголовок миттєво, блоки з'являються по мірі готовності даних — без блокування всієї сторінки.

Метрики та компромісси

Стратегія TTFB TTI SEO Складність
Чистий SSR Високий Середній Відмінно Середня
Чистий CSR Низький Високий Погано Низька
Чистий SSG Мінімальний Мінімальний Відмінно Низька
Гібрид (App Router) Низький Низький Відмінно Висока

Гібридний рендер максимально ефективний, але вимагає розуміння моделі — де проходить межа server/client, як працює кеш, як уникнути waterfall запитів.

Строки реалізації

  • Тиждень 1–2: проектування меж server/client за маршрутами, налаштування Next.js App Router або Nuxt 3
  • Тиждень 3: Server Components для публічних сторінок, Server Actions для мутацій
  • Тиждень 4: Client Components для інтерактивних частин, Suspense-межі
  • Тиждень 5: ISR та кешування для публічного контенту, оптимізація TTFB
  • Тиждень 6: тестування, моніторинг Core Web Vitals, розгортання