关于 static-rendering
面向 Web 开发者的静态渲染指南,介绍 Next.js 的数据获取与路由生成,说明预渲染 HTML 适用于不随请求变化的内容。
主要功能
- 01构建时生成 HTML
- 02构建时获取数据
- 03动态路由预渲染
- 04CDN 部署指导
适用场景
- 01渲染关于和联系页面
- 02发布静态博客文章
- 03生成商品列表页面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ patternsdev/ skills --skill static-rendering安装后在 Claude Code 中输入/static-rendering确认已加载。
详细介绍
静态渲染
根据我们对 SSR 的讨论,我们知道,服务器上的请求处理时间过长会对 TTFB 产生负面影响。同样,对于 CSR,JavaScript 包过大会因为脚本的下载和处理耗时而损害应用的 FCP、LCP 和 TTI。
静态渲染或静态生成(SSG)尝试通过向客户端提供预渲染的 HTML 内容来解决这些问题,这些内容是在构建网站时生成的。
适用场景
- 用于不会因请求而变化的静态内容,例如“关于”页面、博客文章和产品列表
- 如果你希望通过 CDN 提供的静态 HTML 实现尽可能快的 TTFB,这种方式会很有帮助
不适用场景
- 对于每次请求都会变化的高度动态、个性化内容(例如用户仪表盘、实时信息流)
- 数据集过大,导致构建耗时过长,且无法使用 ISR 的情况
- 页面需要身份验证才能访问内容,且无法在构建时预渲染的情况
说明
- 使用
getStaticProps(Pages Router)或异步组件(App Router)在构建时获取数据 - 使用
getStaticPaths/generateStaticParams预渲染动态路由 - 对需要定期更新的页面,可以考虑使用增量静态再生成(ISR)
- 部署到 CDN,以获得边缘缓存性能
详情
系统会预先为用户可以访问的每个路由生成一个静态 HTML 文件。这些静态 HTML 文件可以存放在服务器或 CDN 上,并在客户端请求时获取。
静态文件也可以缓存,从而提高弹性。由于 HTML 响应是预先生成的,服务器上的处理时间几乎可以忽略不计,因此 TTFB 更快,性能也更好。在理想情况下,客户端 JS 应尽可能精简,静态页面应在客户端收到响应后尽快变得可交互。因此,SSG 有助于实现更快的 FCP/TTI。
基本结构
顾名思义,静态渲染适用于静态内容,这类页面无需根据已登录用户进行个性化定制(例如个性化推荐)。因此,网站的“关于我们”“联系我们”页面、博客页面,以及电商应用的产品页面等静态页面,都适合使用静态渲染。Next.js、Gatsby 和 VuePress 等框架都支持静态生成。
Next.js:
// pages/about.js
export default function About() {
return (
<div>
<h1>About Us</h1>
{/* ... */}
</div>
);
}
构建网站时(使用 next build),此页面会预渲染为 HTML 文件 about.html,可通过路由 /about 访问。
使用数据的 SSG
“关于我们”或“联系我们”页面中的静态内容可以直接渲染,无需从数据存储中获取数据。然而,对于单篇博客页面或产品页面等内容,则必须在构建时将数据存储中的数据与特定模板合并,再渲染为 HTML。
列表页面 - 所有项目
在 Next.js 中,可以通过在页面组件中导出函数 getStaticProps() 来实现。构建服务器会在构建时调用此函数来获取数据。
// This function runs at build time on the build server
export async function getStaticProps() {
return {
props: {
products: await getProductsFromDatabase(),
},
};
}
// The page component receives products prop from getStaticProps at build time
export default function Products({ products }) {
return (
<>
<h1>Products</h1>
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</>
);
}
该函数不会包含在客户端 JS 包中,因此甚至可以用来直接从数据库获取数据。
单项详情页面 - 每个项目
对于单项详情页面,可以将函数 getStaticPaths() 与动态路由结合使用。
// pages/products/[id].js
export async function getStaticPaths() {
const products = await getProductsFromDatabase();
const paths = products.map((product) => ({
params: { id: product.id },
}));
// fallback: false means pages that don't have the correct id will 404.
return { paths, fallback: false };
}
// params will contain the id for each generated page.
export async function getStaticProps({ params }) {
return {
props: {
product: await getProductFromDatabase(params.id),
},
};
}
export default function Product({ product }) {
// Render product
}
SSG - 关键考量
-
**大量 HTML 文件:**需要为用户可能访问的每个路由生成单独的 HTML 文件。维护大量 HTML 文件可能颇具挑战。
-
**托管依赖:**要让 SSG 网站速度极快、响应迅速,用于存储和提供 HTML 文件的托管平台也必须足够出色。如果经过优化的 SSG 网站托管在多个 CDN 上,以利用边缘缓存,则可以实现极佳的性能。
-
**动态内容:**每次内容发生变化时,都需要构建并重新部署 SSG 网站。如果内容变更后尚未重新构建并部署网站,显示的内容可能会过时。因此,SSG 不适用于高度动态的内容。