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 来达到效果。

最后

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

相关推荐
KD2 小时前
OpenClaw——让龙虾像真人一样控制桌面的SKILL(macOS版)
github
码事漫谈3 小时前
大模型输出的“隐性结构塌缩”问题及对策
前端·后端
这儿有一堆花3 小时前
前端三件套真的落后了吗?揭开现代 Web 开发的底层逻辑
前端·javascript·css·html5
.Cnn4 小时前
JavaScript 前端基础笔记(网页交互核心)
前端·javascript·笔记·交互
醉酒的李白、4 小时前
Vue3 组件通信本质:Props 下发,Emits 回传
前端·javascript·vue.js
Mark108594 小时前
Hexo + GitHub Pages + GitHub Actions:源码私有、站点公开的 CI/CD 教程
ci/cd·github
anOnion4 小时前
构建无障碍组件之Window Splitter Pattern
前端·html·交互设计
NotFound4864 小时前
实战分享Python爬虫,如何实现高效解析 Web of Science 文献数据并导出 CSV
前端·爬虫·python
徐小夕5 小时前
PDF无限制预览!Jit-Viewer V1.5.0开源文档预览神器正式发布
前端·vue.js·github
WangJunXiang65 小时前
Haproxy搭建Web群集
前端