前言
Open Graph 是一种用来在社交媒体上分享链接时,自动生成预览图的协议,支持的平台有 Facebook、LinkedIn 等。Twitter card 是 Twitter 自己的协议,支持的平台只有 Twitter。
两者都是基于 HTML 的 <meta>
标签实现的。
例如,下面是一个 Open Graph 的例子:
Twitter card 的例子:
各平台会根据这些标签的内容,自动把你发布的链接转换成预览图,如下图所示:
为什么要自动生成
对于我们的网站来说,我们可以在整个网站的 root layout 加上整站的 Open Graph 和 Twitter card 的标签。而对于每篇文章,我们可以手动给每篇文章选择配图。
而大部份情况下,我不想给每篇文章都选择配图,这时候我们就可以生成固定排版格式的配图。
所用技术
- Satori:Satori 是 Vercel 开源的一个工具,可以用来把HTML、CSS 转换成 SVG。
- resvg-js:resvg-js 是一个 Rust 实现的 SVG 渲染引擎,可以用来把 SVG 转换成 PNG。
- Astro:本篇文章是在基于 Astro 的项目中实现的,但核心代码与 Astro 无关,你也可以在其他项目中使用。
整体流程与思路
- 使用 Endpoint 在构建 SSG 时调用生成图片函数。
- 使用 Satori 来按照固定模板生成图片。
- Markdown 文章使用 frontmatter 指定 ogImage。
- 未指定 ogImage 的文章使用自动生成的图片。
- ogImage 通过 Props 传给 layout
- layout 生成需要的 HTML meta 结构
实现
API Endpoints
对于所有的文章,如何触发生成图片逻辑,我们这里使用 Astro 的 Endpoints。当前其他框架也有类似功能,比如 Next.js 和 Nuxt.js。
在 src/posts
文件夹下,建一个 [slug]
文件夹,里面建一个 index.png.ts
文件,文件内容如下:
解释一下上面的代码,因为我们是 SSG 静态生成,所以需要导出一个 getStaticPaths
函数来获取所有的文章。
然后导出 GET
函数,函数中调用了 generateOgImageForPost
函数,也就是接下来生成图片的核心逻辑,返回 Content-Type
为 image/png
的 Response。
这样在打包的时候,就会为所有的文章执行 GET
,生成图片。
生成图片
在 utils
下新建一个 generateOgImages.tsx
文件。
本文件导出一个 generateOgImageForPost
函数,供 Endpoint 调用。
我们使用了 satori
库来生成 svg, 然后使用 resvg
来把 svg 转成 png 格式。
tsx 模板
satori
接收两个参数,第一个是模板,类型是 ReactNode
,第二个是配置项。
在 utils/og-templates
文件夹下新建 post.tsx
:
因为模板是 tsx 文件被导入到 generateOgImages
使用,这也就是为啥 generateOgImages.tsx
要用 tsx 后缀名。
中文字体
其实到这里就可以基本使用了,但是我们想找一个好的中文字体。
于是我在 google fonts 找到了一个叫做 ZCOOLKuaiLe
的字体,把它下载到了 public/fonts
文件夹下。
修改我们的 generateOgImages.tsx
:
通过 fetch 获取字体,然后配置 embedFont: true
及 fonts
数组。
以上就增加了自定义字体的支持,友情提示,选字体的时候一定要看好对中文的支持程度,有的支持不好的会变成 □ 。
PS: 在本地打包时,会去请求 ${SITE.website}/fonts/ZCOOL_KuaiLe/ZCOOLKuaiLe-Regular.ttf
文件,
第一次开发时还没有,就会报错。所以需要先把字体文件上传上去。
支持 emoji
接下来我们想实现可以支持 emoji 的功能,让我们生成的图片更酷炫一点。
再次修改 generateOgImages.tsx
:
以上使用了 loadAdditionalAsset
配置项来处理特殊字符。
我们又引入了两个函数 getIconCode
和 loadEmoji
,那么我们新建 twemoji.ts
文件:
这大段代码是 vercel 根据 twemoji 改的,支持了多种类型的 emoji。我直接抄了过来。
调用方法就是:
这样我们就支持了在生成的图片中显示 emoji 了。
小结
到这里,我们其实就完成了生成图片的核心逻辑。
执行 npm run build
。
可以看到打包时执行了我们写的 Endpoint,为每篇文章生成了图片。
查看 dist/posts
文件夹
访问:http://localhost:4321/posts/astro-auto-gen-og-image.png
接下来,我们说一下 layout 和 markdown 文章 frontmatter,用来生成 OG 所需的 HTML meta 标签。
本部分是使用 Astro 框架,如果你使用其他框架也没关系,核心代码与框架无关,你可以跳过此部分,在其他项目按需配置。
layout 配置
首先我们在 Layout.astro
中,配置如下:
PostDetails 配置
然后是 PostDetails.astro
。
PostDetail 是文章详情页,从文章的 frontmatter 中拿到相应数据,如果文章有自己配置的 ogImage 就用自己的,如果没有,就用文章slug 拼接将要自动生成的 url:
最后传给 Layout。
文章配置
文章的 frontmatter 是由 Astro 的 Content Collections 管理的:
markdown 文章示例
最终效果
在 Twitter 上编辑推文,内容是我们的文章链接,然后发布,效果如下:
总结
至此我们完成了我们想要的全部功能,全部代码在我的博客仓库。Next.js 其实有自己的生成图片功能,也是使用的 Satori
,感兴趣的朋友可以把这套移植到其他系统。
加我微信
liruifengv2333
,进群交流,抱团取暖。
关注公众号 SayHub
,带来更多原创内容。
很高兴见到你,欢迎来玩儿~