هذا المقال للمستوى المتوسط — يفترض إنك شغّلت Cloudflare Worker مرّة قبل كده، وعندك إلمام بـ JSX و SVG، وفاهم تاج og:image في الـ HTML.
اعمل OG Image Generator ديناميكي بـ Satori و Hono — صور سوشيال أوتوماتيكية لكل صفحة
لو كل مقال على موقعك بيشير على X و LinkedIn بنفس صورة الكوفر الثابتة، أنت بتخسر نسبة نقر تقديرية بين 28% و 41% مقارنة بمنافسين بيولّدوا صورة فريدة لكل URL. الحل ميتطلبش حد يفتح Figma كل يوم — هتبني خدمة OG Image دينامكية في 95 سطر TypeScript، تشتغل على Cloudflare Workers بصفر تكلفة على الـ free tier، وترجّع PNG فريد لأي صفحة في أقل من 200ms بدون متصفح ولا headless Chrome.
المشكلة باختصار
الـ Open Graph image (تاج og:image في الـ head) هو أول حاجة بيشوفها أي حد لمّا الـ URL يتشارك في X و LinkedIn و Slack و Discord و Telegram. صورة ثابتة معناها كل مقالاتك بتبان نفس الشكل في الـ feed، وده بيدفن المقال الجديد جنب القديم. صورة دينامكية فيها العنوان والوسم واسم الكاتب بتنتج بطاقة مميزة بصريًا وبترفع نسبة النقر بشكل ملحوظ.
المشكلة الحقيقية مش في الفكرة — المشكلة في توليد الصورة نفسها. لو فتحت Puppeteer جوّه Lambda بتاعتك، الـ cold start بيقفز فوق 2.5 ثانية، استهلاك الذاكرة بيتجاوز 512MB، والتكلفة بتتضاعف. Satori (من Vercel) بيحل ده — بيحوّل JSX لـ SVG بدون متصفح، وبعدين resvg-wasm بياخد الـ SVG ويحوّله لـ PNG داخل WebAssembly. الكل يشتغل في Cloudflare Worker وزنه أقل من 5MB.
مثال للمبتدئ — مطبعة دعوات الأفراح
تخيّل مطبعة بتطبع دعوات أفراح. كل دعوة شكلها واحد، بس الاسم والتاريخ والصاله بتتغيّر. مفيش مصمم بيرسم كل دعوة من الأول؛ في "قالب" واحد، والمطبعة بتحط البيانات في خاناتها وبتطبع. ده بالظبط اللي Satori بيعمله: قالب JSX واحد + بيانات مختلفة (العنوان، الوسم، الكاتب) = صورة فريدة في كل مرة بدون شغل يدوي.
الفرق هنا إن "المطبعة" بتشتغل على شبكة edge عالمية، يعني الصورة بتتولّد قريبة جغرافيًا من اللي بيشاركها، مش من سيرفر بعيد. لو حد في طوكيو شارك مقالك، الصورة بتتولّد من Cloudflare PoP في طوكيو في 80-140ms.
التعريف العلمي — كيف Satori يشتغل تحت الغطا
Satori مكتبة JavaScript مفتوحة المصدر طلعتها Vercel سنة 2022 عشان يستخدموها في صفحات Next.js. بتاخد JSX (مع subset محدود من Flexbox) وبتمرّ الـ tree على layout engine مكتوب بالكامل في JS، بدون V8 isolate تاني، بدون DOM، بدون CSSOM. المخرج SVG نظيف. بعدين resvg (مكتبة Rust مترجمة لـ WebAssembly) بتاخد الـ SVG وبتعمله rasterization لـ PNG بـ Skia-like rendering.
ده معناه إنك بتعمل rendering كامل لصورة 1200x630 في حدود 80–140ms داخل Worker، بدون cold start ملحوظ، وبدون ما تفتح متصفح أصلًا. الفرضية الأساسية: محتاج Flexbox فقط (مفيش CSS Grid، مفيش JS interactivity، مفيش media queries مركّبة).
ليه مش Puppeteer أو Playwright
- الحجم: Puppeteer مع Chromium ≈ 280MB. Worker bundle مع Satori و resvg-wasm ≈ 3.8MB.