mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(site): serve branded OG images dynamically (#1345)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
521774a95b
commit
961766d81d
@@ -7,7 +7,7 @@ import BlogPagination from '@/components/blog/BlogPagination.astro';
|
||||
import BlogPostCard from '@/components/blog/BlogPostCard.astro';
|
||||
import FooterEasterEgg from '@/components/FooterEasterEgg.astro';
|
||||
import JsonLd from '@/components/JsonLd.astro';
|
||||
import { PRODUCTION_URL } from '@/consts';
|
||||
import { BLOG_PAGE_SIZE, PRODUCTION_URL } from '@/consts';
|
||||
import Blog from '@/layouts/Blog.astro';
|
||||
import { createBlogCollectionSchema } from '@/utils/jsonLd/schemas';
|
||||
|
||||
@@ -24,7 +24,7 @@ export const getStaticPaths = (async ({ paginate }) => {
|
||||
}))
|
||||
);
|
||||
|
||||
return paginate(postsWithAuthors, { pageSize: 10 });
|
||||
return paginate(postsWithAuthors, { pageSize: BLOG_PAGE_SIZE });
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
type PostWithAuthors = CollectionEntry<'blog'> & {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
|
||||
import { renderOgImage } from '@/utils/og/render-og-image';
|
||||
import { getOgCacheHeaders, resolveOgRequest } from '@/utils/og/resolve-og-request';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
const imagePromiseCache = new Map<string, Promise<Buffer>>();
|
||||
|
||||
function getCachedOgImage(cacheKey: string, title: string, size: 'og' | 'twitter'): Promise<Buffer> {
|
||||
let pngPromise = imagePromiseCache.get(cacheKey);
|
||||
|
||||
if (!pngPromise) {
|
||||
pngPromise = renderOgImage({ title, size }).catch((error) => {
|
||||
imagePromiseCache.delete(cacheKey);
|
||||
throw error;
|
||||
});
|
||||
imagePromiseCache.set(cacheKey, pngPromise);
|
||||
}
|
||||
|
||||
return pngPromise;
|
||||
}
|
||||
|
||||
export const GET: APIRoute = async ({ params }) => {
|
||||
// Dynamic mode intentionally uses a whitelist of known site paths instead of
|
||||
// allowing arbitrary title or slug inputs.
|
||||
const ogRequest = await resolveOgRequest(params.path);
|
||||
|
||||
if (!ogRequest) {
|
||||
return new Response('Not found', {
|
||||
status: 404,
|
||||
headers: { 'Cache-Control': 'public, max-age=0, must-revalidate' },
|
||||
});
|
||||
}
|
||||
|
||||
const cacheKey = `${ogRequest.size}:${ogRequest.sitePath}`;
|
||||
const png = await getCachedOgImage(cacheKey, ogRequest.title, ogRequest.size);
|
||||
|
||||
return new Response(new Uint8Array(png), {
|
||||
headers: {
|
||||
'Content-Type': 'image/png',
|
||||
...getOgCacheHeaders(),
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user