使用 @vercel/og 库生成动态 Open Graph 图像

本帖由 DeepL 翻译。如有任何翻译错误,请告知我们!

概述

在提供多语言博客文章后,当更改语言时,文本会发生变化,但缩略图不会,因此,当内容是英文而图片是韩文时,看起来很别扭。因此,我需要动态生成图片,于是我研究并找到了 vercel 提供的一个库。

在 Next.js 中设置动态 OG 图像

通过 Vercel 的@vercel/og 库,Next.js 支持动态生成 OG 图像。该功能通过Vercel 函数进行计算和执行。

安装

  • 应用程序路由器项目:无需安装其他软件包(内置)
    • import { ImageResponse } from "next/og"
  • 页面路由器项目npm i @vercel/og 使用命令安装
    • import { ImageResponse } from "@vercel/og

基本用法

造型

像创建组件一样创建组件。这是一个 API,因为它是使用 JSX 语法创建的,但你需要创建一个文件扩展名为jsxtsx 的文件。

您可以像下面这样直接插入样式来创建、

return new ImageResponse(
  <div
    style={{
      height: '100%',
      width: '100%',
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      justifyContent: 'center',
      backgroundColor: '#fff',
      fontSize: 32,
      fontWeight: 600,
    }}
  >
    <div style={{ marginTop: 40 }}>Hello, World</div>
  </div>
)

tw 道具来应用 tailwindCSS 语法。

return new ImageResponse(
  <div
    tw="h-full w-full flex flex-col items-center justify-center bg-white text-xl font-bold"
  >
    <div tw="mt-10">Hello, World</div>
  </div>
)

页路由器项目

/pages/api/og.tsx 路径,并编写以下内容

import { NextRequest } from "next/server";
import { ImageResponse } from "@vercel/og";

export const config = {
  runtime: "edge",
};

export default async function handler(request: NextRequest) {
  const { searchParams } = request.nextUrl;
  const title = searchParams.get("title");
  
  return new ImageResponse(
    (
      <div tw="flex flex-col w-full h-full items-center justify-center bg-white">
        <div tw="bg-gray-50 flex w-full">
          <div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8">
            <h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
              {title}
            </h2>
            <div tw="mt-8 flex md:mt-0">
              <div tw="flex rounded-md shadow">
                <a tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white">
                  시작하기
                </a>
              </div>
              <div tw="ml-3 flex rounded-md shadow">
                <a tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600">
                  더 알아보기
                </a>
              </div>
            </div>
          </div>
        </div>
      </div>
    ),
    {
      width: 1200,
      height: 630,
    },
  );
}

由于 Pages Routrer 不支持 Node.js 运行时,因此必须额外应用以下设置,以便 Vercel 函数在 Edge 运行时中运行。

export const config = {
  runtime: "edge",
};

应用路由器项目

/app/api/og/route.tsx 文件,并写入以下内容Pages 路由器和 App 路由器的唯一区别在于路径和编写方式,但返回的值是相同的。

export async function GET(request: NextRequest) {
  const { searchParams } = request.nextUrl;
  const title = searchParams.get("title");

  // 이하 생략... 
}

正如您在代码中看到的,您可以通过searchParams 动态获取和显示值。

const title = searchParams.get("title");

因此,当您调用以下应用程序接口时,您将在浏览器中看到以下内容/api/og?title=WOW

Image.png

添加自定义字体

为了让外观更 OG,我们来添加自定义字体。鉴于字体文件位于/public/fonts/ 下,我们可以这样写

import { NextRequest } from "next/server";
import { ImageResponse } from "next/og";
import { join } from "path";
import { readFileSync } from "fs";

export async function GET(request: NextRequest) {
  // 생략...
  const fontPath = join(process.cwd(), "public", "fonts", "WONTitle.ttf");
  const fontData = readFileSync(fontPath);
  
  return new ImageResponse(
    (
      <div>
      // 생략...
      </div>
    ),
    {
      width: 1200,
      height: 630,
      fonts: [
        {
          name: "WONTitle",
          data: fontData,
        },
      ],
    },
  );
}

添加图片

你也可以通过导入图片来添加图片。如果存在外部 URL,可以直接输入;如果有本地可用的图片,可以像下面这样使用它

const logoPath = join(
  process.cwd(),
  "public",
  "images",
  "logo",
  `${logo}.png`,
);
const logoBuffer = readFileSync(logoPath);
const logoBase64 = `data:image/png;base64,${logoBuffer.toString("base64")}`;

// ... 생략

return new ImageResponse((
  <img
    alt="og thumbnail"
    tw="absolute -translate-x-1/2 -translate-y-1/2 "
    src={logoBase64}
    width={logoWidth}
    height={logoHeight}
    style={{
      opacity: 0.6,
    }}
/>), ...)

结果

AnimatedImage.gif

我们现在可以动态生成样式相同但不同语言文本不同的缩略图。以前我每次都要进入图片编辑器创建缩略图,现在我想我再也不用这样做了。

🔎参见

❤️ 0
🔥 0
😎 0
⭐️ 0
🆒 0