chore: try fixing compilation on cf

This commit is contained in:
Thomas Camlong
2025-11-17 11:10:16 +01:00
parent 59b8391d03
commit 81d01f8bba
3 changed files with 49 additions and 60 deletions

View File

@@ -2,21 +2,9 @@ import { permanentRedirect, redirect } from "next/navigation"
import { ImageResponse } from "next/og" import { ImageResponse } from "next/og"
import { getCommunityGalleryRecord, getCommunitySubmissionByName, getCommunitySubmissions } from "@/lib/community" import { getCommunityGalleryRecord, getCommunitySubmissionByName, getCommunitySubmissions } from "@/lib/community"
export const runtime = "edge";
export const revalidate = 21600 // 6 hours export const revalidate = 21600 // 6 hours
export async function generateStaticParams() {
const icons = await getCommunitySubmissions()
const validIcons = icons.filter((icon) => icon.name)
if (process.env.CI_MODE === "false") {
return validIcons.slice(0, 5).map((icon) => ({
icon: icon.name,
}))
}
return validIcons.map((icon) => ({
icon: icon.name,
}))
}
export const size = { export const size = {
width: 1200, width: 1200,
height: 630, height: 630,

View File

@@ -1,34 +1,23 @@
import { readFile } from "node:fs/promises" import { ImageResponse } from "next/og";
import { join } from "node:path" import { BASE_URL } from "@/constants";
import { ImageResponse } from "next/og" import { getAllIcons } from "@/lib/api";
import { getAllIcons } from "@/lib/api"
export const revalidate = false export const runtime = "edge";
export const revalidate = false;
export async function generateStaticParams() {
const iconsData = await getAllIcons()
if (process.env.CI_MODE === "false") {
// This is meant to speed up the build process in local development
return Object.keys(iconsData)
.slice(0, 5)
.map((icon) => ({
icon,
}))
}
return Object.keys(iconsData).map((icon) => ({
icon,
}))
}
export const size = { export const size = {
width: 1200, width: 1200,
height: 630, height: 630,
} };
export default async function Image({ params }: { params: Promise<{ icon: string }> }) { export default async function Image({
const { icon } = await params params,
}: {
params: Promise<{ icon: string }>;
}) {
const { icon } = await params;
if (!icon) { if (!icon) {
console.error(`[Opengraph Image] Icon not found for ${icon}`) console.error(`[Opengraph Image] Icon not found for ${icon}`);
return new ImageResponse( return new ImageResponse(
<div <div
style={{ style={{
@@ -46,31 +35,32 @@ export default async function Image({ params }: { params: Promise<{ icon: string
Icon not found Icon not found
</div>, </div>,
{ ...size }, { ...size },
) );
} }
const iconsData = await getAllIcons() const iconsData = await getAllIcons();
const totalIcons = Object.keys(iconsData).length const totalIcons = Object.keys(iconsData).length;
const index = Object.keys(iconsData).indexOf(icon) const index = Object.keys(iconsData).indexOf(icon);
// Format the icon name for display // Format the icon name for display
const formattedIconName = icon const formattedIconName = icon
.split("-") .split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ") .join(" ");
// Read the icon file from local filesystem // Fetch the icon from CDN (Edge Runtime compatible)
let iconData: Buffer | null = null let iconUrl: string | null = null;
try { try {
const iconPath = join(process.cwd(), `../png/${icon}.png`) const iconCdnUrl = `${BASE_URL}/png/${icon}.png`;
console.log(`Generating opengraph image for ${icon} (${index + 1} / ${totalIcons}) from path ${iconPath}`) const response = await fetch(iconCdnUrl);
iconData = await readFile(iconPath) if (response.ok) {
} catch (_error) { const arrayBuffer = await response.arrayBuffer();
console.error(`Icon ${icon} was not found locally`) const base64 = Buffer.from(arrayBuffer).toString("base64");
iconUrl = `data:image/png;base64,${base64}`;
}
} catch (_error) {
console.error(`Icon ${icon} was not found on CDN`);
} }
// Convert the image data to a data URL or use placeholder
const iconUrl = iconData ? `data:image/png;base64,${iconData.toString("base64")}` : null
return new ImageResponse( return new ImageResponse(
<div <div
@@ -96,7 +86,8 @@ export default async function Image({ params }: { params: Promise<{ icon: string
width: 400, width: 400,
height: 400, height: 400,
borderRadius: "50%", borderRadius: "50%",
background: "linear-gradient(135deg, rgba(56, 189, 248, 0.1) 0%, rgba(59, 130, 246, 0.1) 100%)", background:
"linear-gradient(135deg, rgba(56, 189, 248, 0.1) 0%, rgba(59, 130, 246, 0.1) 100%)",
filter: "blur(80px)", filter: "blur(80px)",
zIndex: 2, zIndex: 2,
}} }}
@@ -109,7 +100,8 @@ export default async function Image({ params }: { params: Promise<{ icon: string
width: 500, width: 500,
height: 500, height: 500,
borderRadius: "50%", borderRadius: "50%",
background: "linear-gradient(135deg, rgba(249, 115, 22, 0.1) 0%, rgba(234, 88, 12, 0.1) 100%)", background:
"linear-gradient(135deg, rgba(249, 115, 22, 0.1) 0%, rgba(234, 88, 12, 0.1) 100%)",
filter: "blur(100px)", filter: "blur(100px)",
zIndex: 2, zIndex: 2,
}} }}
@@ -139,7 +131,8 @@ export default async function Image({ params }: { params: Promise<{ icon: string
height: 320, height: 320,
borderRadius: 32, borderRadius: 32,
background: "white", background: "white",
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05)", boxShadow:
"0 25px 50px -12px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05)",
padding: 30, padding: 30,
flexShrink: 0, flexShrink: 0,
position: "relative", position: "relative",
@@ -155,7 +148,10 @@ export default async function Image({ params }: { params: Promise<{ icon: string
}} }}
/> />
<img <img
src={iconUrl || `https://placehold.co/600x400?text=${formattedIconName}`} src={
iconUrl ||
`https://placehold.co/600x400?text=${formattedIconName}`
}
alt={formattedIconName} alt={formattedIconName}
width={260} width={260}
height={260} height={260}
@@ -279,5 +275,5 @@ export default async function Image({ params }: { params: Promise<{ icon: string
{ {
...size, ...size,
}, },
) );
} }

View File

@@ -122,6 +122,8 @@ async function fetchAuthorData(authorId: number) {
} }
} }
const authorDataCache: Record<number, AuthorData> = {};
/** /**
* Cached version of fetchAuthorData * Cached version of fetchAuthorData
* Uses unstable_cache with tags for on-demand revalidation * Uses unstable_cache with tags for on-demand revalidation
@@ -132,10 +134,13 @@ async function fetchAuthorData(authorId: number) {
* across multiple page builds and requests. * across multiple page builds and requests.
*/ */
export async function getAuthorData(authorId: number): Promise<AuthorData> { export async function getAuthorData(authorId: number): Promise<AuthorData> {
return unstable_cache(async () => await fetchAuthorData(authorId), [`author-${authorId}`], { if (authorDataCache[authorId]) {
revalidate: 86400, return authorDataCache[authorId];
tags: ["authors", `author-${authorId}`], }
})()
const data = await fetchAuthorData(authorId);
authorDataCache[authorId] = data;
return data;
} }
/** /**