From a9bb559568917540f3274480ce10564f925f9d85 Mon Sep 17 00:00:00 2001 From: Catalin Pit <25515812+catalinpit@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:56:46 +0200 Subject: [PATCH] fix: avoid opengraph image limit --- .../blog/[post]/opengraph/route.tsx | 77 +++++++++++++++++++ .../src/app/(marketing)/blog/[post]/page.tsx | 8 +- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx new file mode 100644 index 000000000..906ee18cd --- /dev/null +++ b/apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx @@ -0,0 +1,77 @@ +import { ImageResponse } from 'next/og'; +import { NextResponse } from 'next/server'; + +import { allBlogPosts } from 'contentlayer/generated'; + +export const runtime = 'edge'; + +const contentType = 'image/png'; + +const IMAGE_SIZE = { + width: 1200, + height: 630, +}; + +type BlogPostOpenGraphImageProps = { + params: { post: string }; +}; + +export async function GET(_request: Request, { params }: BlogPostOpenGraphImageProps) { + const blogPost = allBlogPosts.find((post) => post._raw.flattenedPath === `blog/${params.post}`); + + if (!blogPost) { + return NextResponse.json({ error: 'Not found' }, { status: 404 }); + } + + // The long urls are needed for a compiler optimisation on the Next.js side, lifting this up + // to a constant will break og image generation. + const [interBold, interRegular, backgroundImage, logoImage] = await Promise.all([ + fetch(new URL('@documenso/assets/fonts/inter-bold.ttf', import.meta.url)).then(async (res) => + res.arrayBuffer(), + ), + fetch(new URL('@documenso/assets/fonts/inter-regular.ttf', import.meta.url)).then(async (res) => + res.arrayBuffer(), + ), + fetch(new URL('@documenso/assets/images/background-blog-og.png', import.meta.url)).then( + async (res) => res.arrayBuffer(), + ), + fetch(new URL('@documenso/assets/logo.png', import.meta.url)).then(async (res) => + res.arrayBuffer(), + ), + ]); + + return new ImageResponse( + ( +
+ {/* @ts-expect-error Lack of typing from ImageResponse */} + og-background + + {/* @ts-expect-error Lack of typing from ImageResponse */} + logo + +

+ {blogPost.title} +

+ +

Written by {blogPost.authorName}

+
+ ), + { + ...IMAGE_SIZE, + fonts: [ + { + name: 'Inter', + data: interRegular, + style: 'normal', + weight: 400, + }, + { + name: 'Inter', + data: interBold, + style: 'normal', + weight: 700, + }, + ], + }, + ); +} diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx index bd5fdb2da..fc65d9772 100644 --- a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx +++ b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx @@ -25,6 +25,12 @@ export const generateMetadata = ({ params }: { params: { post: string } }) => { absolute: `${blogPost.title} - Documenso Blog`, }, description: blogPost.description, + openGraph: { + images: [`${blogPost.href}/opengraph`], + }, + twitter: { + images: [`${blogPost.href}/opengraph`], + }, }; }; @@ -94,7 +100,7 @@ export default function BlogPostPage({ params }: { params: { post: string } }) { - {post.cta && } + {post.cta && } ); }