Реалізація оптимізації зображень, що завантажуються, на сервері

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

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

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

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація оптимізації зображень, що завантажуються, на сервері
Середня
~2-3 робочих дні
Часті питання

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

Етапи розробки
Останні роботи
  • 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

Серверна оптимізація зображень

Серверна оптимізація конвертує завантажені зображення на сучасні формати (WebP, AVIF), підбирає оптимальну якість та розмір, знижує об'єм переданих даних на 40–70%.

Node.js: Sharp pipeline

import sharp from 'sharp';

interface OptimizeOptions {
  maxWidth?: number;
  quality?: number;
  format?: 'webp' | 'avif' | 'jpeg';
}

async function optimizeImage(inputBuffer: Buffer, options: OptimizeOptions = {}): Promise<Buffer> {
  const { maxWidth = 1920, quality = 80, format = 'webp' } = options;

  return sharp(inputBuffer)
    .resize(maxWidth, undefined, {
      withoutEnlargement: true,
      fit: 'inside',
    })
    .toFormat(format, {
      quality,
      effort: 4,  // баланс швидкість/розмір
    })
    .withMetadata({ orientation: undefined })  // убрати EXIF rotation
    .toBuffer();
}

// Middleware для ленивої оптимізації
app.get('/images/:key', async (req, res) => {
  const { key } = req.params;
  const { w, q = '80', f = 'webp' } = req.query;

  // Перевірити кеш
  const cacheKey = `${key}:${w}:${q}:${f}`;
  const cached = await s3.getObject({ Key: `optimized/${cacheKey}.${f}` }).catch(() => null);

  if (cached) {
    return res.type(`image/${f}`).send(await streamToBuffer(cached.Body));
  }

  // Отримати оригінал
  const original = await s3.getObject({ Key: `originals/${key}` });
  const buffer = await streamToBuffer(original.Body);

  // Оптимізувати
  const optimized = await optimizeImage(buffer, {
    maxWidth: w ? parseInt(w as string) : 1920,
    quality: parseInt(q as string),
    format: f as 'webp' | 'avif' | 'jpeg',
  });

  // Кешувати
  await s3.putObject({
    Key: `optimized/${cacheKey}.${f}`,
    Body: optimized,
    ContentType: `image/${f}`,
    CacheControl: 'public, max-age=31536000',
  });

  res.type(`image/${f}`).send(optimized);
});

PHP: оптимізація при завантаженні

use Intervention\Image\Facades\Image;

class ImageOptimizationService
{
    const FORMATS = ['webp', 'avif'];
    const SIZES = [400, 800, 1200, 1920];

    public function process(UploadedFile $file): array
    {
        $image = Image::make($file->getPathname());

        // Убрати EXIF та повернути за орієнтацією
        $image->orientate()->stripExif();

        $paths = [];

        foreach (self::SIZES as $width) {
            if ($image->width() < $width) continue;

            $resized = clone $image;
            $resized->resize($width, null, fn($c) => $c->aspectRatio()->upsize(false));

            foreach (self::FORMATS as $format) {
                $quality = $format === 'avif' ? 60 : 82;
                $key = "images/{$width}w/{$this->generateKey()}.{$format}";

                Storage::disk('s3')->put(
                    $key,
                    $resized->encode($format, $quality)->__toString(),
                    ['CacheControl' => 'public, max-age=31536000']
                );

                $paths[$format][$width] = $key;
            }
        }

        return $paths;
    }
}

HTML: адаптивні зображення з srcset

// Blade хелпер для оптимізованих зображень
function responsive_img(array $paths, string $alt, string $sizes = '100vw'): string
{
    $avifSrcset = collect($paths['avif'] ?? [])->map(fn($path, $width) =>
        Storage::disk('s3')->url($path) . " {$width}w"
    )->join(', ');

    $webpSrcset = collect($paths['webp'] ?? [])->map(fn($path, $width) =>
        Storage::disk('s3')->url($path) . " {$width}w"
    )->join(', ');

    $fallback = Storage::disk('s3')->url(end($paths['webp']));

    return <<<HTML
<picture>
  <source type="image/avif" srcset="{$avifSrcset}" sizes="{$sizes}">
  <source type="image/webp" srcset="{$webpSrcset}" sizes="{$sizes}">
  <img src="{$fallback}" alt="{$alt}" loading="lazy" decoding="async">
</picture>
HTML;
}

Nginx: конвертація WebP на лету

# Віддавати WebP якщо браузер підтримує
map $http_accept $webp_suffix {
    "~*webp"  ".webp";
    default   "";
}

server {
    location ~* \.(jpg|jpeg|png)$ {
        add_header Vary Accept;
        try_files $uri$webp_suffix $uri =404;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Час реалізації

Sharp pipeline при завантаженні з генерацією WebP/AVIF у кількох розмірах: 2–3 дні. З Nginx WebP конвертацією на лету та CDN: 3–4 дні.