Next.js 构建博客之打包SSG

  1. Next.js 构建博客之资源抓取
  2. Next.js 构建博客之博客搭建

这是 Next.js 构建博客的第三篇文章,上一篇文章介绍了博客的搭建过程,这篇文章则重点介绍一下如何将资源打包成 SSG。

SSG 的全称是 Static Site Generation 即静态渲染,不过在介绍之前先说一下主流的渲染方式:

  1. 客户端渲染,我们常见的 Vue、React 等默认就是客户端渲染,不过这种方式最大弊端就是首屏速度以及 seo 抓取,这刚好不符合我们博客场景;
  1. ssr,其实就是代码跑在 nodejs 上,然后输出渲染的 html 字符串,之后浏览器获取 js 资源后执行同构代码,并将 DOM 元素绑定事件等,不过这里也不符合场景,代码最终部署在 GitHub 上其实是没有额外的服务器让我们执行;
  1. SSG,就是将动态数据输出成固定的 html 文件,兼顾了文件缓存以及 seo 的需求,完美符合我们使用场景;

开启 SSG

上一篇中我们列举了一下页面的路由:

  • /:首页
  • pages:分页页面
  • details/:id:详情页面
  • types/:id:分类页面

对于固定的页面我们不需要做什么,但是对于携带 :id 的动态页面,我们需要把所有的条件都枚举出来,只有这样才能输出所有的页面信息,不至于点击某一个文章直接 404 了。

枚举所有条件可以使用 generateStaticParams 完成,这里看一个官方给出的例子:

ts 复制代码
// app/blog/[slug]/page.js
// Return a list of `params` to populate the [slug] dynamic segment
export async function generateStaticParams() {
  const posts = await fetch("https://.../posts").then((res) => res.json());

  return posts.map((post) => ({
    slug: post.slug,
  }));
}

// Multiple versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
export default function Page({ params }) {
  const { slug } = params;
  // ...
}

其中 [slug] 代表 slug 这个必填,下面的 generateStaticParams 函数作用就是把所有 slug 通过数组的形式进行返回出来,之后 Page 就正常渲染即可。

下面抛砖引玉对 types 页面进行改造

tsx 复制代码
import { classification } from "@blog/side-effect";

interface Params {
  id: [string];
}
interface Props {
  params: Params;
  searchParams: Record<string, string>;
}

export function generateStaticParams(): Params[] {
  const result: Params[] = [];
  classification.forEach((value, key) => {
    result.push({
      rest: [key],
    });
  });

  return result;
}

这里就把页面所需的参数给枚举结束,其他页面也这样处理即可,如果页面参数涉及的是多个,例如页面需要 id 和 name,那你也只需要在 generateStaticParams 按照顺序返回即可,例如:

js 复制代码
// app/pages/[...rest]/page.tsx
return [
  {
    rest: [id, name],
  },
  {
    rest: [id, name],
  },
  // ...
];

之后调整 next.config.js 文件

js 复制代码
const nextConfig = {
  // ...
  output: "export",
};

module.exports = nextConfig;

之后在 app/layout.tsx 文件添加

js 复制代码
export const dynamic = "error";

这里防止在代码中引用 SSG 不支持的一些功能,具体不支持功能可以点击查看

动态标题

有一些页面,例如 types 这个分类页面其中标题应当是固定的,如果按照 Next 设置成一个固定的也不太符合要求,幸好可以使用 generateMetadata 函数来完成动态设置。

js 复制代码
import { Metadata } from "next";

// either Static metadata
export const metadata: Metadata = {
  title: "...",
};

// or Dynamic metadata
export async function generateMetadata({ params }) {
  return {
    title: "...",
  };
}

看一下给出的示例,大概就明白如何使用了,不过这里在涉及博客的场景通常有一部分的标题是固定的,例如 yliu 的个人博客| css 选择器讲解,其中前缀可能是固定的,一个个写也太繁琐了,下面就介绍一下如何编写动态标题以及固定前缀。

app/layout.tsx

js 复制代码
export const metadata: Metadata = {
  title: {
    template: `%s | ${data.user.name} 的个人博客`,
    default: `${data.user.name} 的个人博客`,
  },
  description: "记录生活随笔以及技术博客",
};

这里 %s 是占位符,default 则是如果页面没有设置标题默认输出 xxx 的个人博客标题。

app/types/page.tsx

js 复制代码
export async function generateMetadata({
  params: {
    rest: [id],
  },
}: Props) {
  const current = data.label.find((f) => f.id === +id);

  return {
    title: current?.name,
  };
}

这里就达到我们的最终效果了,当然其实 Metadata 对象包含很多属性,例如 description、keywords 等,所以如果想针对每个文章输出关键词都不相同可以使用 generateMetadata 来达到效果。

最后

如果文章有书写错误地方欢迎指出。下一篇会介绍构建以及开发中常见的一些问题,以及如何处理。

相关推荐
子兮曰3 小时前
Bun v1.3.14 深度解析:Image API、HTTP/3、全局虚拟存储与五十项变革
前端·后端·bun
知识领航员4 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
kyriewen4 小时前
今天,百年巨头一次砍了9200人,而一个离职科学家的实话让全网睡不着觉
前端·openai·ai编程
问心无愧05135 小时前
ctf show web 入门42
android·前端·android studio
kyriewen5 小时前
老板逼我上AI,我偷偷在浏览器里跑LLaMA,省下20万API费
前端·react.js·llm
Beginner x_u5 小时前
前端八股整理(手写 02)|数组转树、数组扁平化、随机打乱一个数组
前端·数组·数组转树·数组扁平化
KaMeidebaby5 小时前
卡梅德生物技术快报|禽类成纤维细胞 FISH 实验:鸟类性别染色体基因定位技术实现与数据验证
前端·数据库·其他·百度·新浪微博
天若有情6736 小时前
前端高阶性能优化:跳出传统懒加载与预加载,基于用户行为做轻量预判加载
前端·性能优化
小小小小宇6 小时前
前端转后端:SQL 是什么
前端
张元清7 小时前
React Observer Hooks:7 种监听 DOM 而不写样板代码的方式
前端·javascript·面试