Skip to content

Commit

Permalink
fix: cache og image responses (#1596)
Browse files Browse the repository at this point in the history
* feat: optimize og image generation

* fix(og images): use edge runtime

* fix(linkpreview): catch all routes and double check imageUrl
  • Loading branch information
BrickheadJohnny authored Jan 29, 2025
1 parent 9f2f9c9 commit 98435fa
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 650 deletions.
10 changes: 9 additions & 1 deletion src/components/common/LinkPreviewHead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ type Props = {
path: string
}

const getTimestamp = () => {
const rounded = new Date()
rounded.setMinutes(0)
rounded.setSeconds(0)
rounded.setMilliseconds(0)
return rounded.getTime()
}

const LinkPreviewHead = ({ path }: Props) => {
const url = `https://guild.xyz/api/linkpreview/${Date.now()?.toString()}/${path}`
const url = `https://guild.xyz/api/linkpreview/${getTimestamp()}/${path}`

return (
<Head>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,34 @@ export const config = {
const interFont = loadGoogleFont("Inter", "400")
const interBoldFont = loadGoogleFont("Inter", "700")
const dystopianFont = fetch(
new URL("../../../../../../public/fonts/Dystopian-Black.woff", import.meta.url)
new URL("../../../../../public/fonts/Dystopian-Black.woff", import.meta.url)
).then((res) => res.arrayBuffer())

const handler = async (req, _) => {
const { protocol, host } = req.nextUrl
const baseUrl = `${protocol}//${host}`

const [, urlName, groupUrlName] =
const [, guildUrlName, pageUrlName] =
req.nextUrl?.pathname
?.replace("/api/linkpreview", "")
?.split("/")
?.filter((param) => !!param) ?? []

if (!urlName || !groupUrlName) return new ImageResponse(<></>, { status: 404 })
if (!guildUrlName) return new Response(undefined, { status: 404 })

const [guild, groups, guildRoles]: [Guild, Guild["groups"], Guild["roles"]] =
const [guild, guildRoles, pages]: [Guild, Guild["roles"], Guild["groups"]] =
await Promise.all([
fetch(`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${urlName}`).then(
(res) => res.json()
),
fetch(
`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${urlName}/groups`
`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${guildUrlName}`
).then((res) => res.json()),
fetch(
`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${urlName}/roles`
`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${guildUrlName}/roles`
).then((res) => res.json()),
!!pageUrlName
? fetch(
`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${guildUrlName}/groups`
).then((res) => res.json())
: undefined,
]).catch(() => [null, null, null])

if (!guild?.id)
Expand All @@ -44,13 +46,13 @@ const handler = async (req, _) => {
statusText: "Guild not found",
})

const group = groups?.find((g) => g.urlName === groupUrlName)
const page = pages?.find((p) => p.urlName === pageUrlName)

if (!group)
return new Response(undefined, {
status: 404,
statusText: "Group not found",
})
const name = page?.name ?? guild.name
const image = page?.imageUrl || guild.imageUrl
const roles = !!page
? guildRoles.filter((role) => role.groupId === page.id)
: guildRoles

try {
const [interFontData, interBoldFontData, dystopianFontData] = await Promise.all([
Expand All @@ -59,11 +61,9 @@ const handler = async (req, _) => {
dystopianFont,
])

const roles = guildRoles?.map((role) => role.name)

const safeGroupDescription = group.description?.replaceAll("\n", "")

const imageUrl = group.imageUrl ?? guild.imageUrl
const safeDescription = (
!!page ? page.description : guild.description
)?.replaceAll("\n", "")

return new ImageResponse(
<div
Expand Down Expand Up @@ -141,16 +141,16 @@ const handler = async (req, _) => {
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
style={{
width: imageUrl?.match("guildLogos") ? "20px" : "48px",
height: imageUrl?.match("guildLogos") ? "20px" : "48px",
borderRadius: imageUrl?.match("guildLogos") ? 0 : "50%",
width: image.match("guildLogos") ? "20px" : "48px",
height: image?.match("guildLogos") ? "20px" : "48px",
borderRadius: image?.match("guildLogos") ? 0 : "50%",
}}
src={
imageUrl?.startsWith("http")
? `${baseUrl}/_next/image?url=${imageUrl}&w=48&q=75`
: `${baseUrl}${imageUrl}`
image?.startsWith("http")
? `${baseUrl}/_next/image?url=${image}&w=48&q=75`
: `${baseUrl}${image}`
}
alt={group.name}
alt={name}
/>
</div>
<h1
Expand All @@ -164,7 +164,7 @@ const handler = async (req, _) => {
textOverflow: "ellipsis",
}}
>
{group.name}
{name}
</h1>
</div>

Expand Down Expand Up @@ -214,9 +214,9 @@ const handler = async (req, _) => {
color: "white",
}}
>
{group.description ? (
`${safeGroupDescription?.slice(0, 80)}${
(safeGroupDescription?.length ?? 0) > 80 ? "..." : ""
{safeDescription ? (
`${safeDescription?.slice(0, 80)}${
safeDescription?.length > 80 ? "..." : ""
}`
) : (
<div style={{ display: "flex", flexDirection: "column" }}>
Expand Down Expand Up @@ -260,6 +260,9 @@ const handler = async (req, _) => {
</div>
</div>,
{
headers: {
"Cache-Control": "s-maxage=3600", // 1 hour
},
width: 800,
height: 450,
fonts: [
Expand Down
Loading

0 comments on commit 98435fa

Please sign in to comment.