在 Next.js 动态路由中生成元数据(metadata)

힘센캥거루
2024년 12월 16일
4
28

为了进行搜索引擎优化,我在搜索如何插入 metadata 的过程中,看到了 velog 上 Doeunnkimm 的文章,于是就在静态地注入元数据。

开始写文章之后,我就希望在动态路由中,为每一篇文章设置不同的 metadata。

所以也当作复习,记录一次。

1. 代码

首先,在上面提到的 velog 中拿到的代码如下:

// 먼저 기본적으로 필요한 메타 데이터를 설정한다.
const META = {
  title: "블로그 제목",
  siteName: "사이트이름",
  description: "블로그에 대한 대략적인 설명",
  keyword: ["배열", "형태의", "키워드"],
  url: "https://sample.kr",
  googleVerification: "xxx", //구글 서치콘솔
  naverVerification: "xxx", //네이버 서치어드바이저
  ogImage: "https://sample.kr/assets/thumbnail.png", // 썸네일,
} as const;

// getMetadata 함수를 이용해 metadata를 설정한다.
// 아래 함수 하나면 대부분의 사이트에서 필요한 metadata는 끝난다.
export const getMetadata = (metadataProps?: generateMetadataProps) => {
  const { title, description, asPath, ogImage } = metadataProps || {};

  const TITLE = title ? `${title} | 블로그 제목` : META.title;
  const DESCRIPTION = description || META.description;
  const PAGE_URL = asPath ? asPath : "";
  const OG_IMAGE = ogImage || META.ogImage;

  const metadata: Metadata = {
    metadataBase: new URL(META.url),
    alternates: {
      canonical: PAGE_URL,
    },
    title: TITLE,
    description: DESCRIPTION,
    keywords: [...META.keyword],
    openGraph: {
      title: TITLE,
      description: DESCRIPTION,
      siteName: TITLE,
      locale: "ko_KR",
      type: "website",
      url: PAGE_URL,
      images: {
        url: OG_IMAGE,
      },
    },
    verification: {
      google: META.googleVerification,
      other: {
        "naver-site-verification": META.naverVerification,
      },
    },
    twitter: {
      title: TITLE,
      description: DESCRIPTION,
      images: {
        url: OG_IMAGE,
      },
    },
    icons: {
      icon: "/favicon/favicon.ico",
    },
  };

  return metadata;
};

然后在 layout.tsx 中调用这段代码来使用。

生成 metadata 并将其导出后,就可以为主页生成元数据。

import "./globals.css";
import { Metadata } from "next";
import { getMetadata } from "@/utils/getMetadata";

// 메타데이터 객체를 내보냄
export const metadata: Metadata = {
  // 전개연산자 ..,를 이용해 객체를 가져온다.
  ...getMetadata(),

  // 만일 다른 제목을 쓰고 싶다면 아래와 같이 하면 된다.
  ...getMetadata({ title: "다른제목" }),
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <body className="h-svh">
        <div>
          <div className="mx-auto max-w-7xl p-6 lg:px-8">{children}</div>
        </div>
      </body>
    </html>
  );
}

进入自己的网站后按 F12,然后查看 <head> 标签,就可以确认 metadata。

在 Next.js 动态路由中生成元数据(metadata)-1

2. 动态路由与 metadata

在动态路由中,我使用了 generateMetadata 函数。

相关说明可以参考上面那篇博客,或 Nextjs 官方文档

在 Next.js 动态路由中生成元数据(metadata)-2

这篇文章的关键在于:在生成 metadata 时,可以利用动态路由中使用的对象

我是通过 slug 和包含文章列表的 Json 来生成元数据的。

export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}) {
  const { slug } = await params;

  //카테고리 목록 json을 호출함
  const categoryData = fs.readFileSync(categoryJsonPath, "utf-8");
  const categorys: postCardFrontMatter[] = JSON.parse(categoryData);

  // 현재의 slug와 url이 동일한 것을 1개 찾아 반환함.
  const baseMetaData = categorys.find(
    (category) => category.postUrlPath === slug
  );

  //이것을 이용해 메타데이터 설정
  const metadata: Metadata = {
    ...getMetadata({
      title: baseMetaData?.data.title,
      description: baseMetaData?.data.description,
      asPath: `https://earthscience.kr/posts/${slug}`,
      ogImage:
        baseMetaData?.data.thumbnail &&
        `https://earthscience.kr/posts/${slug}/${baseMetaData.data.thumbnail}`,
    }),
  };
  return metadata;
}

3. 后记

一般大家都经常使用 Facebook 的 分享调试工具

不过我没有 Facebook 账号,所以就直接用 KakaoTalk 来测试了。

缺点是图片显示出来要花一点时间。

在 Next.js 动态路由中生成元数据(metadata)-3

一开始图片是看不到的,第二天再看的时候图片就能正常显示了。

一点一点地做出来,感觉还是挺有趣的。

관련 글

Next.js 全栈博客开发记
Next.js 全栈博客开发记
在第一次接触网页开发大约 1 年之后,我开始想着想要拥有一个属于自己的博客。于是我就大概花了 6 个月几乎只埋头做这件事。前端部分的功能,参考金度亨先生的博客就已经足够了。我用 mdx 搭建起一个博客,其实连一周都没花到。事实上,仅靠前端也并不会给博客运营带来什么大问题。有一阵子我也觉得,只要写 m...
使用 Caddy 实现 Next.js 无停机部署(本地服务器)
使用 Caddy 实现 Next.js 无停机部署(本地服务器)
每次一有想在主页上加点什么的念头就去 build,结果中间好像偶尔会有人访问。于是 Search Console 上的分数开始一点点往下掉。觉得这样不行,就开始思考要怎么做无停机部署。1. 两个项目文件夹 + 两个终端答案出乎意料地简单:开两个终端。在一个终端里 build,另一个终端里让服务器跑着...
谷歌搜索索引自动化 - Web Search Indexing API
谷歌搜索索引自动化 - Web Search Indexing API
继上次搞完 IndexNow 之后,也决定在谷歌这边做一下自动化。查了一下,发现谷歌是通过一个叫 Web Search Indexing 的 API 来支持这个功能的。1. 适用范围官方文档中,这个 API 正式支持的范围是招聘公告和流媒体视频服务。说是为了给对实时性要求高的内容创建索引用的,但搜了...
搜索索引生成自动化 - IndexNow
搜索索引生成自动化 - IndexNow
在向 Bing 提交站点收录时才发现,Bing 提供了一个叫做 IndexNow 的功能。核心在于,可以利用 API Key,在写完文章的瞬间就立刻发起索引请求。只要用 fetch 写出类似下面这样的请求,并把它串联到「写文章」流程里,就可以在把文章保存到 DB 的同时发送索引生成请求。POST /...
被入侵的 Nextjs、React 服务器经历
被入侵的 Nextjs、React 服务器经历
我最初接触到这次安全问题是在 12 月 5 日凌晨。据说在 React 中可以在未认证的情况下进行远程代码执行。看到这条新闻后,我虽然告诉了别人,但总觉得自己应该没事,就什么想法也没有地略过了。1. 发现被入侵的痕迹结果当我想登录更新博客代码时,在终端里发现了有命令被执行过的痕迹。/bin/sh:...
在博客中添加多语言功能(NextJS、next-intl、Vercel AI SDK)
在博客中添加多语言功能(NextJS、next-intl、Vercel AI SDK)
最近我觉得博客需要多语言功能。于是决定用 next-intl 来实现多语言服务。1.i18n首先,在做多语言服务时有一些必须遵守的原则。这被称为 internationalization,单词太长,所以把首字母 i 和尾字母 n,以及中间 18 个字母合在一起,写成 i18n。1) i18n 的原则...

댓글을 불러오는 중...