javascript

Next.js 15 в Hikasami: Глубокая оптимизация рендеринга, загрузки данных и производительности

  • пятница, 28 февраля 2025 г. в 00:00:08
https://habr.com/ru/companies/hikasami/articles/886220/

Введение

В эпоху цифрового контента каждая миллисекунда загрузки страницы может существенно повлиять на пользовательский опыт. В Hikasami, платформе, предоставляющей потоковое аниме и азиатские медиа для пользователей СНГ, наша цель — обеспечить мгновенную загрузку страниц, минимизировать задержки, а также гарантировать актуальность данных. Для этого мы внедрили Next.js 15, который открыл перед нами возможности глубокой оптимизации:

  • Оптимизированное серверное рендеринг (SSR) с прогрессивным кешированием.

  • Гибридная стратегия кеширования API и динамическое обновление данных.

  • Использование Edge Functions для минимизации задержек по регионам.

  • Гибкая адаптация Gravity UI под SSR.

  • Максимальная оптимизация загрузки видео контента.

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


Архитектура рендеринга в Next.js 15

SSR (Server-Side Rendering) и прогрессивное кеширование

Server‑Side Rendering (SSR) позволяет Next.js динамически формировать HTML на сервере перед отправкой клиенту. Однако использование SSR без продуманного кеширования может приводить к высокой нагрузке на сервер и увеличению Time To First Byte (TTFB).

Теоретическое обоснование выбора SSR

SSR обладает рядом преимуществ перед традиционным клиентским рендерингом (CSR, Client‑Side Rendering) и статической генерацией (SSG, Static Site Generation):

  • Более высокая индексируемость контента — поисковые системы получают уже отрендеренный HTML, что улучшает SEO.

  • Лучший UX для пользователей с медленным интернетом — контент загружается сразу, а не после получения и исполнения JavaScript.

  • Более быстрая начальная загрузка по сравнению с CSR, так как нет необходимости в полном выполнении JavaScript до появления контента.

Однако без должного кеширования SSR может привести к нагрузке на сервер и значительным задержкам в обработке запросов. Именно поэтому мы реализовали прогрессивное кеширование с использованием Redis и CDN.

Проблемы, с которыми мы столкнулись:

  1. Высокий TTFB на страницах с динамическими данными.

  2. Повышенная нагрузка на базу данных (PostgreSQL) при частых запросах.

  3. Задержки при доступе пользователей из отдалённых регионов.

Анализ альтернативных подходов

  1. Классический SSR без кеширования — отказались из‑за высокой нагрузки на сервер и значительного увеличения TTFB.

  2. Полностью статическая генерация (SSG) — подходит для контента, который редко обновляется, но у нас динамические данные (рейтинги, новинки, рекомендации).

  3. Гибридный подход (SSR + ISR + CDN) — оказался оптимальным, так как позволил кешировать контент и обновлять его по мере необходимости.

Наше решение:

  • Внедрение Redis для кеширования HTML‑ответов SSR.

  • Оптимизация пула соединений PostgreSQL через pgxpool.

  • Использование Edge Functions для распределённого рендеринга.

  • Настройка Cloudflare CDN для агрессивного кеширования API и статики.

Пример SSR с кешированием в Redis:

import { getAnimeById } from '@/lib/api';
import { redis } from '@/lib/redis';

export async function getServerSideProps(context) {
  const { id } = context.params;
  const cacheKey = `anime_${id}`;

  let anime = await redis.get(cacheKey);
  if (!anime) {
    anime = await getAnimeById(id);
    await redis.set(cacheKey, JSON.stringify(anime), 'EX', 60); // Кеш на 60 сек
  }

  return { props: { anime: JSON.parse(anime) } };
}

ISR (Incremental Static Regeneration) и гибкая стратегия обновления данных

ISR позволяет Next.js регенерировать страницы на лету без полной пересборки проекта.

Анализ альтернативных решений

  1. Чистый SSR — может перегрузить сервер при высоком количестве запросов.

  2. Чистый SSG — требует полной пересборки сайта для обновления данных.

  3. ISR с гибкой стратегией кеширования — позволяет обновлять данные на основе гибридного подхода.

Наше гибридное решение кеширования:

  1. Динамическое обновление популярных страниц с частыми запросами.

  2. Менее популярные страницы обновляются реже.

  3. Ручное триггерное обновление через WebSockets.

  4. Гибридное кеширование ISR + CDN для минимизации серверных нагрузок.

Пример ISR с динамическим обновлением:

export async function getStaticProps() {
  const res = await fetch('https://api.hikasami.com/anime/top');
  const topAnime = await res.json();

  return {
    props: { topAnime },
    revalidate: 30, // Обновление раз в 30 сек
  };
}

Gravity UI: SSR-проблемы и их решение

Gravity UI изначально не поддерживала SSR, что приводило к ошибкам гидратации.

Анализ альтернативных решений

  1. Использование другой UI‑библиотеки (например, Chakra UI) — потребовало бы значительного рефакторинга проекта.

  2. Ожидание исправлений в Gravity UI — могло занять месяцы, а нам требовалось решение «здесь и сейчас».

  3. Форк и адаптация Gravity UI под SSR — оказалось наиболее эффективным решением.

Наше решение:

  • Перенос кода библиотеки в проект и адаптация под SSR.

  • Глубокая переработка серверного рендеринга компонентов.

На текущий момент разработка Next.js‑ветки Gravity UI активизировалась, но наше пользовательское решение остаётся стабильным и отказоустойчивым.


Итоги

Переход на Next.js 15 позволил:

  • Снизить TTFB на 40%.

  • Оптимизировать кеширование API и SSR.

  • Гибко адаптировать Gravity UI под SSR.

  • Максимально ускорить загрузку видео контента через CDN.

Перспективы дальнейшего развития

  • Внедрение AI‑рекомендаций на основе пользовательского поведения.

  • Улучшение мобильного UX и расширение PWA‑функциональности.

  • Дальнейшее исследование распределённого рендеринга через Edge Functions.