Реалізація Partial Hydration для оптимізації веб-застосунку

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

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

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

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація Partial Hydration для оптимізації веб-застосунку
Складна
~3-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

Реалізація Partial Hydration для оптимізації веб-застосунку

Повна гідрація (Full Hydration) — коли браузер завантажує весь JS-бандл застосунку та оживляє весь DOM, включаючи компоненти, які ніколи не стануть інтерактивними. Статичний заголовок, список статей, футер — все гідрується. Прямі втрати: зайвий JS, зайві CPU, повільний TTI.

Partial Hydration — гідрація тільки тих компонентів, які їй потребують. Статичний контент залишається інертним HTML. JS завантажується тільки для інтерактивних островків.

Проблема Full Hydration

Типова сторінка блогу:
- Header (статичний)         → гідрувати? Навіщо?
- Navigation (статичний)     → гідрувати? Навіщо?
- ArticleContent (MDX)       → гідрувати? Навіщо?
- Comments (інтерактивні)    → ПОТРІБНА гідрація
- ShareButtons (onClick)     → ПОТРІБНА гідрація
- Footer (статичний)         → гідрувати? Навіщо?

Без partial hydration: завантажується весь React (~45 KB) + весь код компонентів
З partial hydration: завантажується тільки код Comments + ShareButtons

Реалізація в Astro (Islands Architecture)

Astro реалізує partial hydration через директиви client:*:

---
// src/pages/article/[slug].astro
import ArticleHeader from '@/components/ArticleHeader.astro';  // Серверний
import ArticleContent from '@/components/ArticleContent.astro'; // Серверний
import CommentSection from '@/components/CommentSection.tsx';   // React, потребує гідрації
import ShareWidget from '@/components/ShareWidget.svelte';      // Svelte, потребує гідрації
import NewsletterForm from '@/components/NewsletterForm.vue';   // Vue, потребує гідрації

const { slug } = Astro.params;
const article = await getArticle(slug);
---

<html>
  <body>
    <!-- Нулевий JS — чистий HTML -->
    <ArticleHeader title={article.title} author={article.author} />
    <ArticleContent content={article.content} />

    <!-- Гідрація при появленні у viewport -->
    <CommentSection articleId={article.id} client:visible />

    <!-- Гідрація при першому взаємодії -->
    <ShareWidget url={Astro.url.href} client:idle />

    <!-- Негайна гідрація (критичний контент) -->
    <NewsletterForm client:load />
  </body>
</html>

Директиви гідрації:

Директива Коли завантажується JS
client:load Одразу при завантаженні сторінки
client:idle Після requestIdleCallback (браузер не займаний)
client:visible Коли компонент входить у viewport
client:media="..." При совпаданні медіа-запиту
client:only="react" Тільки на клієнті, без SSR

Реалізація в Next.js через динамічний імпорт

import dynamic from 'next/dynamic';

// Ці компоненти НЕ включаються у initial bundle
const CommentSection = dynamic(() => import('@/components/CommentSection'), {
  ssr: false,
  loading: () => <CommentsSkeleton />,
});

const VideoPlayer = dynamic(() => import('@/components/VideoPlayer'), {
  ssr: false, // Немає сенсу рендерити на сервері
});

const HeavyChart = dynamic(() => import('@/components/analytics/HeavyChart'), {
  ssr: false,
  loading: () => <div className="h-64 animate-pulse bg-gray-100 rounded" />,
});

// Гідрація при появленні у viewport — нативний IntersectionObserver
function LazyHydrate({ children, rootMargin = '200px' }) {
  const [hydrated, setHydrated] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => { if (entry.isIntersecting) setHydrated(true); },
      { rootMargin }
    );
    if (ref.current) observer.observe(ref.current);
    return () => observer.disconnect();
  }, []);

  return <div ref={ref}>{hydrated ? children : <div style={{ minHeight: '1px' }} />}</div>;
}

// Використання
export default function ArticlePage({ article }) {
  return (
    <article>
      <ArticleHeader article={article} /> {/* Серверний, 0 JS */}
      <ArticleBody content={article.content} /> {/* Серверний, 0 JS */}

      <LazyHydrate>
        <CommentSection articleId={article.id} />
      </LazyHydrate>
    </article>
  );
}

Прогресивна гідрація

Гідруйте компоненти послідовно, не блокуючи main thread:

'use client';
import { useEffect, useState } from 'react';

// Планувальник гідрації через requestIdleCallback
function useIdleHydration(delay = 0): boolean {
  const [ready, setReady] = useState(false);

  useEffect(() => {
    let id: number;

    if ('requestIdleCallback' in window) {
      id = requestIdleCallback(() => setReady(true), { timeout: delay || 2000 });
    } else {
      id = setTimeout(() => setReady(true), delay) as unknown as number;
    }

    return () => {
      'requestIdleCallback' in window
        ? cancelIdleCallback(id)
        : clearTimeout(id);
    };
  }, [delay]);

  return ready;
}

function IdleComponent({ children, fallback }: IdleProps) {
  const ready = useIdleHydration(1000);
  return ready ? children : fallback;
}

Вимірювання ефекту

Інструменти для оцінки до та після partial hydration:

# Webpack Bundle Analyzer
npx @next/bundle-analyzer

# Astro Check: які компоненти додають JS
npx astro check

# Lighthouse CLI для автоматизації
npx lighthouse https://example.com --output json \
  --only-categories=performance \
  | jq '.categories.performance.score'

Метрики, які змінюються:

Метрика Очікуване поліпшення
Total Blocking Time (TBT) -40–70%
Time to Interactive (TTI) -30–60%
JS Parse/Execute час -50–80%
Lighthouse Performance Score +10–25 балів

Коли partial hydration недоцільна

Partial Hydration не має сенсу для:

  • SPA з багатою інтерактивністю на кожній сторінці
  • Застосунків, де майже всі компоненти клієнтські
  • Дашбордів за авторизацією — SEO не важливий, JS завантажується один раз

Максимальна користь на публічних контентних сторінках: блоги, документація, каталоги, лендинги.

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

  • Тиждень 1: аудит JS-бандла, виявлення компонентів без клієнтської логіки, профілювання TTI
  • Тиждень 2–3: розмітка компонентів на серверні/клієнтські, внедрення директив (client:visible, client:idle) або dynamic() з ssr:false
  • Тиждень 4: LazyHydrate обгортки для контенту нижче фолду, вимірювання метрик
  • Тиждень 5: регресійне тестування, Lighthouse CI у конвеєрі, документація