Prerequisites
This post requires you to read satori’s docs first
Create a static file endpoint
A neat feature in Astro is that you can use static file endpoint to generate files, even other than HTML.
Make the getStaticPaths function first. Below is just an example—if you have other ways to retrieve paths feel free to write it yourself.
export async function getStaticPaths() {
const posts = await getCollection("posts");
return posts.map((post) => ({
params: {
id: post.id,
},
props: {
data: post.data,
post: post,
},
}));
}
Load fonts. For me I put my font in the /public folder. Load it using Node.js’ readFile
function. Also, make sure to not load variable font.
const interFontData = await readFile(
resolve(
dirname(fileURLToPath(import.meta.url)),
"../../../public/styles/fonts/inter/Inter-Regular.ttf",
),
);
Create static file endpoints. While Satori supports JSX, as far as I know, you can not use .jsx/.tsx files as the static file endpoint. So, sadly, I need to write the layout in JavaScript object.
const interFontData = await readFile(
resolve(
dirname(fileURLToPath(import.meta.url)),
"../../../public/styles/fonts/inter/Inter-Regular.ttf",
),
);
export const GET: APIRoute = async ({ props }) => {
const svg = await satori(
{
/** React nodes represented as JavaScript object. Stripped due to length. **/
},
{
width: 1200,
height: 630,
fonts: [
{
name: "Inter Regular",
data: interFontData,
style: "normal",
},
],
},
);
};
At this point, Satori generates SVG file. But, this format is not usable as an OG image. As such, we need to convert it using Resvg.
const interFontData = await readFile(
resolve(
dirname(fileURLToPath(import.meta.url)),
"../../../public/styles/fonts/inter/Inter-Regular.ttf",
),
);
export const GET: APIRoute = async ({ props }) => {
const svg = await satori(
{
/** React nodes represented as JavaScript object. Stripped due to length. **/
},
{
width: 1200,
height: 630,
fonts: [
{
name: "Inter Regular",
data: interFontData,
style: "normal",
},
],
},
);
+
+ const resvg = new Resvg(svg);
+ const png = resvg.render().asPng();
+
+ return new Response(png);
};
That’s it.