Оптимизация тяжёлых image gallery в React: от CDN до lazy loading

#react#performance#image-optimization

Последний месяц я решаю задачу, знакомую многим frontend-разработчикам: React-приложение с галереями, где каждая содержит сотни high-res изображений. Первый же деплой показал, что стандартный подход «кидаем картинки в public/assets» не работает уже на 50+ файлах. Вот что выяснилось на практике.

Local vs. External: когда выносить ассеты

Хранение изображений прямо в проекте — это technical debt в чистом виде. Наблюдения:

Когда выносить: сразу. Даже для MVP я теперь использую облачное хранилище (S3-совместимое или Firebase Storage), а для production — связку S3 + CDN. Исключение — критически важные статические assets типа логотипа.

CDN и ресайзинг: Cloudinary vs. ручная настройка

Популярный совет — использовать специализированные сервисы типа Cloudinary или Imgix. Они действительно удобны для:

Но в 2024 году их цена часто избыточна. Альтернатива — свой CDN с трансформациями:

// Пример для AWS Lambda + Sharp
export const handler = async (event) => {
  const { key, edits } = event.queryStringParameters;
  const image = await s3.getObject({ Bucket: 'my-bucket', Key: key }).promise();
  const processed = await sharp(image.Body).resize(edits).toFormat('webp').toBuffer();
  return { statusCode: 200, body: processed.toString('base64') };
};

Такой подход окупается при >10K изображений в месяц, но требует настройки кэширования в CloudFront.

Lazy loading без layout shift

Даже с CDN важно правильно загружать изображения. Мой текущий стек:

  1. Intersection Observer API для настоящего lazy loading (не только ниже fold)
  2. CSS aspect-ratio + резерв для старых браузеров:
.image-wrapper {
  aspect-ratio: 16/9;
  @supports not (aspect-ratio: 16/9) {
    &::before { float: left; padding-top: 56.25%; content: ''; }
  }
}
  1. Blur-плейсхолдеры через SVG или низкокачественные превью (LQIP):
<img
  src="image.webp"
  placeholder="data:image/svg+xml;base64,..."
  loading="lazy"
/>

Готовые компоненты vs. кастомные решения

Для галерей пробовал:

Сейчас склоняюсь к гибридному варианту: беру базовую сетку из пакета и дорабатываю под проект. Например, добавление IntersectionObserver для предзагрузки соседних изображений в lightbox.

Главный урок

Оптимизация изображений — это не про «установи один плагин и забудь». Нужен комплекс:

  1. Правильное хранение (никаких assets/ в репозитории)
  2. CDN с трансформациями (готовый сервис или свой вариант)
  3. Грамотная подгрузка (lazy loading + placeholder)
  4. Адекватный выбор компонентов

Для небольших проектов достаточно Cloudinary + готового gallery-пакета. Для масштабных — своя инфраструктура с балансом между стоимостью и скоростью.


Попробуй сам: DigitalOcean — $200 кредитов для новых пользователей.


Источник: https://www.reddit.com/r/reactjs/comments/1uuffb6/what_is_the_best_solution_for_heavy_image/