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

最后

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

相关推荐
m0_748256785 分钟前
SpringBoot 依赖之Spring Web
前端·spring boot·spring
web1350858863533 分钟前
前端node.js
前端·node.js·vim
m0_5127446434 分钟前
极客大挑战2024-web-wp(详细)
android·前端
若川43 分钟前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点1 小时前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
m0_748256563 小时前
如何解决前端发送数据到后端为空的问题
前端
请叫我飞哥@3 小时前
HTML5适配手机
前端·html·html5
@解忧杂货铺5 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js