# πŸš€ Quick Start: @vercel/og + Quoter ## ⚑ 5-минутная настройка ### 1. Установка зависимостСй ```bash npm install @vercel/og ``` ### 2. Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ API endpoint ```typescript // pages/api/og.tsx (Next.js) import { ImageResponse } from '@vercel/og' export const config = { runtime: 'edge' } export default function handler(req) { const { searchParams } = new URL(req.url) const title = searchParams.get('title') ?? 'Hello World' return new ImageResponse( (
{title}
), { width: 1200, height: 630 } ) } ``` ### 3. Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с Quoter ```typescript // utils/quoter.ts export async function uploadToQuoter(imageBuffer: Buffer, filename: string, token: string) { 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, }) return response.text() // URL Ρ„Π°ΠΉΠ»Π° } ``` ### 4. ИспользованиС ```typescript // ГСнСрация OG изобраТСния const ogResponse = await fetch('/api/og?title=My%20Amazing%20Post') const imageBuffer = Buffer.from(await ogResponse.arrayBuffer()) // Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Π² Quoter const quoterUrl = await uploadToQuoter(imageBuffer, 'og-image.png', userToken) // ИспользованиС Π² meta tags ``` ## 🎨 Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ с ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Ρ„ΠΎΠ½Π° ```typescript // pages/api/og-advanced.tsx import { ImageResponse } from '@vercel/og' export default async function handler(req) { const { searchParams } = new URL(req.url) const title = searchParams.get('title') const imageUrl = searchParams.get('image') // Quoter URL // Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· Quoter let backgroundImage = null if (imageUrl) { const imageResponse = await fetch(imageUrl) const buffer = await imageResponse.arrayBuffer() backgroundImage = `data:image/jpeg;base64,${Buffer.from(buffer).toString('base64')}` } return new ImageResponse( (
{/* Π—Π°Ρ‚Π΅ΠΌΠ½Π΅Π½ΠΈΠ΅ для читаСмости */}
{/* Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ */}

{title}

), { width: 1200, height: 630 } ) } ``` ## πŸ“± React Hook для удобства ```typescript // hooks/useOgImage.ts import { useState } from 'react' export function useOgImage() { const [loading, setLoading] = useState(false) const generateAndUpload = async (title: string, backgroundImage?: string) => { setLoading(true) try { // Π“Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ OG ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ const ogUrl = `/api/og?title=${encodeURIComponent(title)}${ backgroundImage ? `&image=${encodeURIComponent(backgroundImage)}` : '' }` const response = await fetch(ogUrl) const buffer = await response.arrayBuffer() // Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π² Quoter const formData = new FormData() const blob = new Blob([buffer], { type: 'image/png' }) formData.append('file', blob, `og-${Date.now()}.png`) const uploadResponse = await fetch('/api/upload-to-quoter', { method: 'POST', body: formData, }) return await uploadResponse.text() } finally { setLoading(false) } } return { generateAndUpload, loading } } // ИспользованиС Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ function MyComponent() { const { generateAndUpload, loading } = useOgImage() const handleCreateOg = async () => { const quoterUrl = await generateAndUpload('My Post Title', '/existing-image.jpg') console.log('OG image uploaded to:', quoterUrl) } return ( ) } ``` ## ⚑ Production Tips ### ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ```typescript // Cache OG images for 24 hours export default function handler(req) { const response = new ImageResponse(/* ... */) response.headers.set('Cache-Control', 'public, max-age=86400') response.headers.set('CDN-Cache-Control', 'public, max-age=86400') return response } ``` ### Error Handling ```typescript export default async function handler(req) { try { return new ImageResponse(/* ... */) } catch (error) { console.error('OG generation failed:', error) // Fallback ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ return new Response('Failed to generate image', { status: 500 }) } } ``` ### Environment Variables ```bash # .env.local QUOTER_API_URL=https://quoter.staging.discours.io QUOTER_AUTH_TOKEN=your_jwt_token NEXT_PUBLIC_OG_BASE_URL=https://yoursite.com/api/og ``` ## πŸ”— ΠŸΠΎΠ»Π΅Π·Π½Ρ‹Π΅ ссылки - [Полная докумСнтация ΠΏΠΎ ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ](./vercel-og-integration.md) - [Quoter API Reference](./api-reference.md) - [Vercel OG Official Docs](https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation) --- πŸ’‹ **Π£ΠΏΡ€ΠΎΡ‰Π΅Π½ΠΈΠ΅**: Один endpoint для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ, ΠΎΠ΄ΠΈΠ½ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ - ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ ΠΊΠΎΠ΄Π°, максимум Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°!