4.4 KiB
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:
image/avif, если клиент поддерживает AVIF и preset разрешает AVIF.image/webp, если клиент поддерживает WebP и preset разрешает WebP.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.