在Astro中使用Satori、Sharp和Astro端点设置静态OG(Open Graph)图像
Posted on April 7, 2023 from Nanyang,China你是否将链接分享给朋友,并想知道预览图片是从哪里来的?
那就是 Open Graph Protocol,这是一组可丰富链接的HTML <meta>
扩展,最初由Facebook发明。
本博客文章描述了如何在构建时生成这些图片,使用的是 Astro web framework。
大多数现有的指南(包括Vercel官方的 OG Image Generation)都使用函数动态生成OG图像。 虽然这种方式没有问题,但我真的希望我的图像在构建时静态生成;这样更快、更便宜,也更酷。
构建你的图片
首先要做的是弄清楚你的OG图像应该是什么样子的。 我们将使用Vercel的 Satori,这是一个可以将HTML树渲染成SVG的JavaScript库。 Vercel还提供了一个很棒的 OG Image Playground,在这里你可以玩耍并快速获得结果。
将大小设置为1200×630px,因为这是Facebook在 他们的指南 中推荐的大小。 在布局时大量使用Flexbox,并在确定布局时启用调试模式。 A Complete Guide to Flexbox是一个很棒的资源。
创建一个Astro端点
在Playground中构建了一张漂亮的图片?那么让我们开始吧。 安装Satori以生成SVG和 sharp 以将其转换为PNG:
$ npm install satori sharp
然后创建一个端点,例如 pages/og-image.png.ts
,其中包含以下代码:
import fs from "fs/promises";
import satori from "satori";
import sharp from "sharp";
import type { APIRoute } from 'astro';
export const get: APIRoute = async function get({ params, request }) {
const robotoData = await fs.readFile("./public/fonts/roboto/Roboto-Regular.ttf");
const svg = await satori(
{
type: "h1",
props: {
children: "Hello world",
style: {
fontWeight: "bold"
}
}
},
{
width: 1200,
height: 630,
fonts: [
{
name: "Roboto",
data: robotoData,
weight: "normal",
style: "normal",
},
],
}
);
const png = await sharp(Buffer.from(svg)).png().toBuffer();
return new Response(png, {
headers: {
"Content-Type": "image/png",
},
});
}
你可以在上面的代码中看到一个缺点,即Astro不支持TSX端点,所以我们需要使用类似React元素的对象。
你还需要始终提供一个字体,因为它将被嵌入到图像中。 上面的示例中我使用了 Roboto, Inter 或 Open Sans 是其他可靠的免费无衬线字体(选择WOFF或TTF/OTF,不支持WOFF2)。
运行 astro dev
并导航到端点(在我们的示例中为 :3000/og-image.png),查看生成的图像。
为集合中的每个项目生成图像
一旦你在函数中找到喜欢的图像,你可以为整个集合批量创建它们。
假设你有一个 blog
集合,你的博文位于 pages/blog/:slug/index.astro
。
创建一个 pages/blog/:slug/og-image.png.ts
,其中包含你的API路由和导出的 getStaticPaths
函数:
import { getCollection, getEntryBySlug } from "astro:content";
export async function getStaticPaths() {
const posts = await getCollection("blog");
return posts.map((post) => ({
params: { slug: post.slug },
props: post,
}));
}
export const get: APIRoute = async function get({ params, request }) {
// ...
}
现在运行 astro build
,你将看到它为你站点上的每篇博文静态生成了一个OG图像。
处理图片
图片(如字体)需要嵌入到SVG中。 我找到的最简单的方法是使用 data urls, 首先将文件读取为Base64字符串,例如:
const myImageBase64 = (await fs.readFile("./public/my-image.png")).toString("base64");
然后在Satori中将其设置为 backgroundImage
或 src
属性,例如:
{
type: "div",
props: {
style: {
backgroundImage: `url('data:image/png;base64,${myImageBase64}')`,
}
}
}
请注意,Satori不支持 backgroundSize: cover
,所以如果你有这种情况,你需要使用 image-size 和一些数学计算来自己构建它。
在HTML中设置OG标签
现在只剩下一件事要做,就是在你的 <head>
中链接到你的OG图像。
有两个属性你可能想在图像中使用:og:image
和 twitter:image
。
<meta property="og:image" content="/blog/og-image.png" />
<meta property="twitter:image" content="/blog/og-image.png" />
在集合中使用动态路径,自动使用正确的图像。 请查看 Open Graph protocol 了解更多关于Open Graph元扩展的信息。
进一步链接和总结
如果你想看到实际的工作代码(我知道我经常这样做),请查看驱动我书评OG图像的端点:
pages/books/[...slug]/og-image.png.ts
。
这是它的样子:书评的OG图像。