Files
image-platform/docs/next-image-provider.md
2026-05-12 07:54:32 +03:00

4.4 KiB
Raw Blame History

Next/image Provider

image-platform должен работать как custom image provider для next/image.

Next.js contract

Next.js custom loader получает только:

  • src;
  • width;
  • quality.

Поэтому public image URL должен принимать эти параметры напрямую и сам запускать read-through генерацию при miss.

Remote source loader config

Remote source mode нужен для сценария, где consumer project уже имеет изображение в public или внешний image URL и хочет получить srcset без предварительной регистрации asset.

В Next.js приложении используется loaderFile:

// next.config.js
module.exports = {
  images: {
    loader: "custom",
    loaderFile: "./src/image-platform-loader.js",
    qualities: [75, 80],
  },
}

Пример loader:

"use client"

import { createImagePlatformNextLoader } from "@image-platform/client"

export default createImagePlatformNextLoader({
  baseUrl: process.env.NEXT_PUBLIC_IMAGE_PLATFORM_URL,
  preset: "card",
  project: process.env.NEXT_PUBLIC_IMAGE_PLATFORM_PROJECT,
  sourceBaseUrl: process.env.NEXT_PUBLIC_SITE_ORIGIN,
})

Пример использования:

import Image from "next/image"

export function ProductCard() {
  return <Image src="/images/product.jpg" width={640} height={420} alt="Product" />
}

Если src относительный, sourceBaseUrl превращает его в абсолютный source URL, например https://site.example.com/images/product.jpg. Если src уже абсолютный, он передаётся как есть.

Public URL

Remote source URL:

GET /p/{project}/remote/{preset}?src={sourceUrl}&w={width}&q={quality}&f=auto

Пример:

https://img.example.com/p/acme/remote/card?src=https%3A%2F%2Fsite.example.com%2Fimages%2Fproduct.jpg&w=640&q=80&f=auto

Managed asset URL:

GET /images/{assetId}/v{version}/{preset}?w={width}&q={quality}&f=auto

Route реализован в Fastify Gateway. Для card ширина должна входить в static preset allowlist: 320, 640, 960.

Пример:

https://img.example.com/images/asset_123/v4/card?w=640&q=80&f=auto

Для managed asset src не должен быть source URL. Это должен быть versioned platform identifier, например asset_123/v4/card. Source URL хранится в PostgreSQL и не раскрывается в public image URL.

v{version} меняется при обновлении source image. Старые URL можно кэшировать как immutable без purge.

Для remote source src является исходным URL. Этот режим не immutable по умолчанию: Gateway отдаёт GATEWAY_REMOTE_CACHE_CONTROL, потому что источник может быть mutable.

Format auto

f=auto выбирает output format по Accept header:

  1. image/avif, если клиент поддерживает AVIF и preset разрешает AVIF.
  2. image/webp, если клиент поддерживает WebP и preset разрешает WebP.
  3. image/jpeg или original fallback.

Для auto format обязательны headers:

Vary: Accept
Cache-Control: public, max-age=31536000, immutable
Content-Type: image/avif | image/webp | image/jpeg

CDN и Gateway L1 cache должны учитывать Vary: Accept, иначе можно отдать AVIF клиенту без AVIF support.

Read-through behavior

client -> CDN -> Fastify gateway -> L1 memory -> Backend -> RabbitMQ -> Worker -> imgproxy -> S3

Поведение:

  • CDN HIT: backend не вызывается.
  • Gateway L1 HIT: backend не вызывается.
  • Gateway L1 MISS: Gateway вызывает Backend internal ensure endpoint.
  • S3 HIT: Backend отдаёт bytes Gateway, Gateway кладёт result в L1.
  • S3 MISS: Backend ставит RabbitMQ job, Worker генерирует variant через external imgproxy, сохраняет в S3, обновляет PostgreSQL, Backend возвращает bytes Gateway.

Так достигается Cloudinary-like поведение: первый запрос создаёт derived asset, следующие запросы отдаются из cache/storage.