likes
comments
collection
share

Next.js 构建博客之打包SSG

作者站长头像
站长
· 阅读数 3

Next.js 构建博客之打包SSG

如果你想看已经部署博客的地址可以点击查看,代码仓库地址点击查看

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

  1. 客户端渲染,我们常见的 Vue、React 等默认就是客户端渲染,不过这种方式最大弊端就是首屏速度以及 seo 抓取,这刚好不符合我们博客场景;

Next.js 构建博客之打包SSG

  1. ssr,其实就是代码跑在 nodejs 上,然后输出渲染的 html 字符串,之后浏览器获取 js 资源后执行同构代码,并将 DOM 元素绑定事件等,不过这里也不符合场景,代码最终部署在 GitHub 上其实是没有额外的服务器让我们执行;

Next.js 构建博客之打包SSG

  1. SSG,就是将动态数据输出成固定的 html 文件,兼顾了文件缓存以及 seo 的需求,完美符合我们使用场景;

Next.js 构建博客之打包SSG

开启 SSG

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

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

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

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

// 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 页面进行改造

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 按照顺序返回即可,例如:

// app/pages/[...rest]/page.tsx
return [
  {
    rest: [id, name],
  },
  {
    rest: [id, name],
  },
  // ...
];

之后调整 next.config.js 文件

const nextConfig = {
  // ...
  output: "export",
};

module.exports = nextConfig;

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

export const dynamic = "error";

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

动态标题

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

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

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

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

app/types/page.tsx

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

最后

转载自:https://juejin.cn/post/7310101543775961088
评论
请登录