# 🖼️ Интеграция @vercel/og с Quoter Proxy ## 📋 Обзор `@vercel/og` - это мощная библиотека для генерации динамических OpenGraph изображений на Edge Runtime. Quoter теперь поддерживает интеграцию с @vercel/og для создания красивых социальных превью. ## 🔄 Изменения в архитектуре ### Удалённая функциональность (Legacy) - ❌ `src/overlay.rs` - удалена встроенная логика наложения текста - ❌ `src/Muller-Regular.woff2` - удалён встроенный шрифт - ❌ `imageproc`, `ab_glyph` dependencies - удалены из Cargo.toml - ❌ Параметр `s=` в API - больше не поддерживается ### Новая архитектура - ✅ @vercel/og обрабатывает генерацию OpenGraph изображений - ✅ Quoter выступает как proxy для статических файлов - ✅ Improved caching и performance optimization ## 🚀 Настройка @vercel/og ### 1. Установка пакета ```bash npm install @vercel/og # или yarn add @vercel/og ``` ### 2. Базовый пример использования ```typescript import { ImageResponse } from '@vercel/og' export default function handler(req: Request) { return new ImageResponse( (
Hello world!
), { width: 1200, height: 600, }, ) } ``` ## 🔗 Интеграция с Quoter Proxy ### Сценарий использования 1. @vercel/og генерирует динамические OpenGraph изображения 2. Результат сохраняется через Quoter API 3. Quoter обслуживает изображения с кэшированием и оптимизацией ### Настройка Endpoint для @vercel/og ```typescript // pages/api/og/[...slug].ts import { ImageResponse } from '@vercel/og' import { NextRequest } from 'next/server' export const config = { runtime: 'edge', } export default async function handler(req: NextRequest) { try { const { searchParams } = new URL(req.url) // Получение параметров const title = searchParams.get('title') ?? 'Default Title' const description = searchParams.get('description') ?? 'Default Description' const imageUrl = searchParams.get('image') // URL изображения из Quoter // Загрузка изображения через Quoter proxy let backgroundImage = null if (imageUrl) { try { const imageResponse = await fetch(imageUrl) const imageBuffer = await imageResponse.arrayBuffer() backgroundImage = `data:image/jpeg;base64,${Buffer.from(imageBuffer).toString('base64')}` } catch (error) { console.error('Failed to load image from Quoter:', error) } } return new ImageResponse( (
{/* Overlay для читаемости */}
{/* Контент */}

{title}

{description}

), { width: 1200, height: 630, } ) } catch (e: any) { console.log(`${e.message}`) return new Response(`Failed to generate the image`, { status: 500, }) } } ``` ## 📤 Сохранение сгенерированных изображений в Quoter ### Пример интеграции ```typescript // utils/saveToQuoter.ts export async function saveOgImageToQuoter( imageBuffer: Buffer, filename: string, token: string ): Promise { const formData = new FormData() const blob = new Blob([imageBuffer], { type: 'image/png' }) formData.append('file', blob, filename) const response = await fetch('https://quoter.staging.discours.io/', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, }, body: formData, }) if (!response.ok) { throw new Error(`Failed to upload to Quoter: ${response.statusText}`) } const result = await response.text() return result // URL загруженного файла } // Использование async function generateAndSaveOgImage(title: string, description: string, token: string) { // Генерация изображения через @vercel/og const ogResponse = await fetch(`/api/og?title=${encodeURIComponent(title)}&description=${encodeURIComponent(description)}`) const imageBuffer = Buffer.from(await ogResponse.arrayBuffer()) // Сохранение в Quoter const filename = `og-${Date.now()}.png` const quoterUrl = await saveOgImageToQuoter(imageBuffer, filename, token) return quoterUrl } ``` ## 🎨 Расширенные возможности ### Кастомные шрифты ```typescript // Загрузка шрифтов const font = fetch( new URL('./assets/Muller-Regular.woff', import.meta.url) ).then((res) => res.arrayBuffer()) // Использование в ImageResponse return new ImageResponse(
Custom font text
, { width: 1200, height: 630, fonts: [ { name: 'Muller', data: await font, style: 'normal', }, ], } ) ``` ### Динамическая загрузка изображений из Quoter ```typescript async function loadQuoterImage(imageId: string): Promise { const quoterUrl = `https://quoter.staging.discours.io/${imageId}` try { const response = await fetch(quoterUrl) if (!response.ok) throw new Error(`HTTP ${response.status}`) const buffer = await response.arrayBuffer() return `data:image/jpeg;base64,${Buffer.from(buffer).toString('base64')}` } catch (error) { console.error('Failed to load image from Quoter:', error) return '' // fallback } } ``` ## 🔧 Конфигурация Quoter для @vercel/og ### Environment Variables ```bash # .env.local QUOTER_API_URL=https://quoter.staging.discours.io QUOTER_AUTH_TOKEN=your_jwt_token_here ``` ### Типы для TypeScript ```typescript // types/quoter.ts export interface QuoterUploadResponse { url: string filename: string size: number contentType: string } export interface OgImageParams { title: string description?: string backgroundImage?: string template?: 'default' | 'article' | 'profile' } ``` ## 📊 Performance & Caching ### Оптимизация производительности - ✅ @vercel/og работает на Edge Runtime - ✅ Quoter обеспечивает кэширование с ETag - ✅ Автоматическое сжатие изображений - ✅ CDN-дружественные HTTP заголовки ### Рекомендации по кэшированию ```typescript // Добавление cache headers для OG изображений export default function handler(req: NextRequest) { const imageResponse = new ImageResponse(/* ... */) // Кэширование на 1 день imageResponse.headers.set('Cache-Control', 'public, max-age=86400, s-maxage=86400') imageResponse.headers.set('CDN-Cache-Control', 'public, max-age=86400') return imageResponse } ``` ## 🚀 Deployment ### Vercel 1. Deploy @vercel/og endpoints на Vercel 2. Configure Quoter URL в environment variables 3. Set up proper CORS если нужно ### Standalone 1. Use Next.js standalone mode 2. Configure Quoter integration 3. Deploy где угодно с Node.js support ## 🔍 Troubleshooting ### Распространённые проблемы 1. **"Failed to load image from Quoter"** - Проверьте доступность Quoter API - Убедитесь в правильности токена авторизации 2. **"Font loading failed"** - Убедитесь, что шрифты доступны в build time - Используйте правильные MIME types 3. **"Image generation timeout"** - Оптимизируйте сложность layout - Уменьшите размер внешних ресурсов ## 📚 Дополнительные ресурсы - [Vercel OG Documentation](https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation) - [Quoter API Reference](./api-reference.md) - [Performance Best Practices](./monitoring.md) --- 💋 **Упрощение через разделение ответственности**: @vercel/og занимается генерацией, Quoter - хранением и доставкой.