介绍
- SSG,英文全称“Static Site Generation”,中文翻译“静态站点生成”。
- SSG 会在构建阶段,就将页面编译为多个静态的 HTML 文件。就是根据动态数据输出成固定的 html 文件,兼顾了文件缓存以及 seo 的需求。
- 比如打开一篇博客文章页面,既然所有人看到的内容都是一样的,没有必要在用户请求页面的时候,服务端再请求接口。干脆先获取数据,提前编译成 HTML 文件,等用户访问的时候,直接返回 HTML 文件。这样速度会更快。再配上 CDN 缓存,速度就更快了。
项目配置
next.config.ts文件
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: 'export',
};
export default nextConfig;
- 将构建模式调整为'export',即可让nextjs项目跑build指令时,输出静态html文件,接着便可以上传到对应的服务器上来进行访问。
应用
静态路由
无需特别操作,按照正常的写法,将一个页面分为服务端区域(纯静态)与客户端区域
服务端组件
export default async function Page() {
// This fetch will run on the server during `next build`
const res = await fetch('https://api.example.com/...')
const data = await res.json()
return <main>
...
</main>
}
服务端组件不允许使用state和effect,也就是说不能进行状态管理,这也意味着只能写一些简单的静态页面,当然,针对一些静态官网项目,这是很好用的
客户端组件
'use client'
export default function Page() {
const [data,setData] = useState()
useEffect(()=>{
const data = await fetch('https://api.example.com/...')
setData(data)
})
return <div>
{data.name}
</div>
}
开发和传统SPA应用没有区别,其实nextjs也可以开发SPA应用,只要将所有组件定义为客户端组件即可
总的来说,按照上述两个写法,能满足大多数简单项目的开发了 如,要求SEO的部分,尽量使用服务端组件来生成静态html内容 强交互部分,如各类小工具,则使用客户端组件来生成动态部分
动态路由
// app/blog/[slug]/page.js
// 获取一个总的slug列表
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;
const res = await fetch(`https://api.example.com/${slug}`)
const data = await res.json()
// ...
}
其中 [slug] 代表 slug 这个必填,下面的 generateStaticParams 函数作用就是把所有 slug 通过数组的形式进行返回出来,之后自行选择客户端组件或是服务端组件即可 在构建阶段,nextjs会根据posts数组,输出/blog/ 下数个页面
动态meta
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// read route params
const id = (await params).id
// fetch data
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// optionally access and extend (rather than replace) parent metadata
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }: Props) {}
静态数据api
文件:app/data.json/route.ts
export async function GET() {
return Response.json({ name: 'Lee' })
}
ssg不支持的功能
- 不能确定数据的动态路由
- 重定向
- 动态api路由
- 中间件等等服务端高级特性