|
1 | 1 | /** |
2 | | - * Default OG image — systematic isolation test. |
3 | | - * Tests increasingly complex HTML to find the breaking point. |
| 2 | + * Default OG image — bypass HTMLRewriter by using React elements directly. |
| 3 | + * workers-og's og() accepts React.ReactNode, skipping parseHtml entirely. |
4 | 4 | */ |
5 | 5 | import type { APIRoute } from "astro"; |
6 | 6 | import { ImageResponse } from "workers-og"; |
7 | | -import { generateDefaultOgHtml, loadFonts } from "../../../lib/og-utils"; |
| 7 | +import { loadFonts } from "../../../lib/og-utils"; |
8 | 8 |
|
9 | 9 | export const prerender = false; |
10 | 10 |
|
11 | 11 | export const GET: APIRoute = async ({ url }) => { |
12 | | - const level = url.searchParams.get("level") || "full"; |
13 | | - |
14 | | - // Level 1: Single div (known working) |
15 | | - const html1 = '<div style="display:flex;width:1200px;height:630px;background:#000;color:#fff;font-size:48px;align-items:center;justify-content:center">Hello World</div>'; |
16 | | - |
17 | | - // Level 2: Two nested divs |
18 | | - const html2 = '<div style="display:flex;width:1200px;height:630px;background:#000"><div style="display:flex;color:#fff;font-size:48px;align-items:center;justify-content:center;width:100%;height:100%">Hello World</div></div>'; |
19 | | - |
20 | | - // Level 3: Column layout with 3 children |
21 | | - const html3 = '<div style="display:flex;width:1200px;height:630px;background:#000;padding:60px"><div style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:space-between"><div style="display:flex;color:#fff;font-size:24px">Top</div><div style="display:flex;color:#fff;font-size:48px">Middle</div><div style="display:flex;color:#fff;font-size:16px">Bottom</div></div></div>'; |
22 | | - |
23 | | - // Level 4: Logo with emoji + spans |
24 | | - const html4 = '<div style="display:flex;width:1200px;height:630px;background:#000;padding:60px"><div style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:space-between"><div style="display:flex;align-items:center;gap:12px"><div style="font-size:40px">🐱</div><div style="display:flex;font-size:24px;font-weight:700;color:#fff"><span>CodingCat</span><span style="color:#7c3aed">.dev</span></div></div><div style="display:flex;color:#fff;font-size:48px">Title</div><div style="display:flex;color:#888;font-size:16px">codingcat.dev</div></div></div>'; |
25 | | - |
26 | | - // Level 5: Full template |
27 | | - const html5 = generateDefaultOgHtml({ title: "Test Title" }); |
28 | | - |
29 | | - const htmlMap: Record<string, string> = { "1": html1, "2": html2, "3": html3, "4": html4, "5": html5, full: html5 }; |
30 | | - const html = htmlMap[level] || html5; |
31 | | - |
32 | | - if (url.searchParams.get("mode") === "dump") { |
33 | | - return new Response(html, { headers: { "Content-Type": "text/plain" } }); |
34 | | - } |
35 | | - |
36 | 12 | try { |
37 | | - const response = new ImageResponse(html, { |
| 13 | + // Pass a React element directly — bypasses HTMLRewriter parseHtml |
| 14 | + const element = { |
| 15 | + type: "div", |
| 16 | + props: { |
| 17 | + style: { |
| 18 | + display: "flex", |
| 19 | + width: 1200, |
| 20 | + height: 630, |
| 21 | + background: "#000", |
| 22 | + color: "#fff", |
| 23 | + fontSize: 48, |
| 24 | + alignItems: "center", |
| 25 | + justifyContent: "center", |
| 26 | + }, |
| 27 | + children: "Hello World", |
| 28 | + }, |
| 29 | + }; |
| 30 | + |
| 31 | + const response = new ImageResponse(element as any, { |
38 | 32 | width: 1200, |
39 | 33 | height: 630, |
40 | 34 | fonts: loadFonts(), |
41 | 35 | }); |
42 | 36 |
|
43 | 37 | const buffer = await response.arrayBuffer(); |
44 | 38 | if (buffer.byteLength === 0) { |
45 | | - return new Response(JSON.stringify({ error: "Empty buffer", level }), { |
| 39 | + return new Response(JSON.stringify({ error: "Empty buffer" }), { |
46 | 40 | status: 500, headers: { "Content-Type": "application/json" }, |
47 | 41 | }); |
48 | 42 | } |
49 | 43 |
|
50 | 44 | return new Response(buffer, { |
51 | | - headers: { "Content-Type": "image/png", "Content-Length": buffer.byteLength.toString() }, |
| 45 | + headers: { |
| 46 | + "Content-Type": "image/png", |
| 47 | + "Content-Length": buffer.byteLength.toString(), |
| 48 | + }, |
52 | 49 | }); |
53 | 50 | } catch (e: any) { |
54 | | - return new Response(JSON.stringify({ error: e.message, level }), { |
| 51 | + return new Response(JSON.stringify({ error: e.message, stack: e.stack }), { |
55 | 52 | status: 500, headers: { "Content-Type": "application/json" }, |
56 | 53 | }); |
57 | 54 | } |
|
0 commit comments