构建期分页:静态站的翻页为什么不该用查询参数

列表分页在构建时切成静态页,第 N 页是一个真实路由。没有客户端分页逻辑,也不用查询串,翻页就是纯链接跳转。

这个站的博客列表每页 6 篇。第二页的地址是 /zh/blog/page/2/,一个构建期生成的真实 HTML 文件,而不是 /zh/blog/?page=2。

为什么不用查询参数

静态托管下,?page=2 对服务器和爬虫都是同一个 HTML。分页内容要么靠 JS 在客户端切——那意味着首屏得拿到全部文章数据,把性能优势交回去;要么让服务器读查询串——那就不是纯静态了。构建期切页绕开了这两个选项。

页码怎么收敛

切片与页码收敛是纯逻辑,放在 lib/paginate.ts,零 import:

export function paginate(items, page, size) {
  const total = totalPages(items.length, size);
  const current = clampPage(page, total);
  const start = (current - 1) * step;
  return {
    items: items.slice(start, start + step),
    page: current,
    totalPages: total,
    hasPrev: current > 1,
    hasNext: current < total,
  };
}

超范围的页码收敛到末页,而不是返回空页;size 非法时按 1 页处理,免得除零。这些分支都有断言覆盖。

路由由篇数推导

server/paths.ts 的 blogPagedPaths 按总篇数算出要生成几页,第 1 页是列表页本身,不重复生成。加一篇文章,新页自动出现,不用手写路由。

组件只在多页时渲染

只有一页时 pagination 是 null,分页组件整体不渲染,页面底部也不会多出一排孤零零的「1」。

代价

每页一份 HTML,文章变多时页面数线性增长;翻页是整页跳转,不保留任何筛选状态。这个站不需要筛选,所以第二条不构成损失。

← 返回文章列表

评论

…