在 Next.js 项目中接入 next-sitemap:自动生成站点地图与 robots.txt(pages router 示例详解)
本篇技术指南基于当前仓库中的 with-next-sitemap 官方示例,完整讲解如何为基于 pages router 的 Next.js 应用接入 next-sitemap 工具,在每次生产构建后自动为全部静态预渲染页面(含大量动态路由页面)生成 sitemap.xml 与 robots.txt,并支持将超大型站点地图自动拆分为多个文件。读完本文后,你将掌握:示例工程的文件组织、next-sitemap.config.js 中每个配置项的语义与默认行为、postbuild 自动挂载机制、动态路由页面被纳入站点地图的底层前提,以及如何与 App Router 原生 sitemap.ts 文件约定做选型对比。
示例概览:一次构建、全站自动收录
仓库中的 examples/with-next-sitemap/ 目录演示了最核心的用法:无需在页面里手写任何 sitemap 相关代码,仅靠一个配置文件 + 一条 npm script 钩子,next-sitemap 就会在你执行 next build 之后,扫描构建产物中所有可被静态输出的页面,把它们整理成符合 Sitemaps XML 协议的站点地图,并顺带生成搜索引擎会主动请求的 robots.txt。
该示例的完整文件清单如下:
| 路径 | 作用 |
|---|---|
| examples/with-next-sitemap/pages/index.tsx | 静态首页,展示指向 5 个动态页面的链接 |
| examples/with-next-sitemap/pages/[dynamic].tsx | 动态路由页面,通过 getStaticPaths 预渲染 10000 个路径 |
| examples/with-next-sitemap/next-sitemap.config.js | next-sitemap 的配置文件(核心) |
| examples/with-next-sitemap/package.json | 声明依赖并挂载 postbuild 钩子 |
| examples/with-next-sitemap/tsconfig.json | TypeScript 编译配置 |
| examples/with-next-sitemap/README.md | 官方示例说明 |
值得强调的是,示例工程刻意只展示构建时静态生成页面的自动化收集场景——next-sitemap 还能生成 robots.txt,并且具备把大型站点地图切分为多个文件、再通过索引文件聚合的能力,这两点正对应示例配置中 generateRobotsTxt 与 robotsTxtOptions 两个字段。
接入三步走:依赖、配置、构建钩子
第一步:安装依赖
next-sitemap 是构建期的 Node.js 命令行工具,应当放在 devDependencies 中。本示例固定的版本为 next-sitemap@3.1.22,同时使用 next@latest(示例编写时锁定 react / react-dom 为 ^18.2.0),完整依赖声明见 examples/with-next-sitemap/package.json:
"devDependencies": {
"@types/node": "18.7.18",
"@types/react": "^18.0.20",
"next-sitemap": "3.1.22",
"typescript": "^4.8.3"
}
第二步:编写配置文件
在项目根目录创建 next-sitemap.config.js。示例中给出的完整配置如下,文件原样保存在 examples/with-next-sitemap/next-sitemap.config.js:
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: "https://example.com",
generateRobotsTxt: true,
// optional
robotsTxtOptions: {
additionalSitemaps: [
"https://example.com/my-custom-sitemap-1.xml",
"https://example.com/my-custom-sitemap-2.xml",
"https://example.com/my-custom-sitemap-3.xml",
],
},
};
逐项说明这几个配置字段的语义与实操要点:
siteUrl(必填):站点的公开根地址,所有生成 URL 的前缀都来源于此。示例中使用占位地址https://example.com,实际部署时必须替换为你自己的域名,否则搜索引擎抓取到的 URL 将全部指向错误站点。注意不要在末尾加斜杠。generateRobotsTxt(布尔):设为true时,工具在生成站点地图的同时输出robots.txt,其中会自动声明对sitemap的引用,相当于省去了手写 robots 文件再维护其中 sitemap 地址的重复劳动。robotsTxtOptions.additionalSitemaps(数组):本字段标注为optional(可选)。它用于把并非由 next-sitemap 生成、但确实存在的其他 sitemap 地址追加声明进robots.txt。典型场景是:某一份内容由 CMS、博客系统或第三方服务维护并已单独产出 sitemap,你希望搜索引擎经由你站点的robots.txt一并发现它们。示例中追加了 3 个自定义 sitemap 地址。- 文件首行
@type {import('next-sitemap').IConfig}是一个 JSDoc 类型标注:由于next-sitemap自带 TypeScript 类型定义,使用支持类型提示的编辑器编写本文件时即可获得字段级自动补全与拼写检查。
第三步:挂载 postbuild 钩子
仅安装依赖和写配置还不够,关键在于让生成动作在构建完成后自动触发。示例在 package.json 的 scripts 中加了这样一条:
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"postbuild": "next-sitemap"
}
原理是 npm 的 pre/post 脚本钩子机制:只要 scripts 中存在名为 postbuild 的脚本,那么任何一次 npm run build(此处即 next build)在成功结束后都会自动接着执行 postbuild。因此这里的执行链路是:
npm run build
└─ next build ← 产出 .next 产物与预渲染页面清单
└─ next-sitemap ← 读取产物,扫描全部预渲染路径,生成 sitemap 与 robots.txt
这正是该示例能实现"构建完站点地图自动新鲜出炉"的关键设计,也是将 next-sitemap 集成进现有 CI/CD 部署流水线的最简做法——不需要额外改动任何平台脚本。
页面侧的设计:被收录的页面从哪来
为了演示 next-sitemap 能覆盖"静态页 + 海量动态预渲染页"两类场景,示例精心构造了两个页面。
静态首页
pages/index.tsx 是一个不含任何数据请求的纯静态页面,仅用 next/link 列出指向 /page-1 ~ /page-5 的 5 个链接:
import Link from "next/link";
const IndexPage = () => (
<>
<h1>Hello World Page</h1>
<ol>
<li>
<Link href="/[dynamic]" as="/page-1">
Link to dynamic page 1
</Link>
</li>
{/* …… page-2 至 page-5,省略号仅用于排版示意,原文件为完整 5 项 */}
</ol>
</>
);
export default IndexPage;
这段代码同时演示了 pages router 动态路由的经典跳转写法:href 声明路由模板 /[dynamic],as 则给出浏览器地址栏实际展示的伪静态路径 /page-N。
一万条路径的动态页
pages/[dynamic].tsx 是本示例最具教学价值的部分。它定义了 [dynamic] 动态路由段,并通过 getStaticPaths 一次性预渲染 10000 个路径:
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [...Array(10000)].map((_, index) => ({
params: {
dynamic: `page-${index}`,
},
})),
fallback: false,
};
};
也就是说构建后会真实产出 page-0 至 page-9999 共 10000 个静态 HTML 文件。fallback: false 表示未枚举到的路径直接返回 404,这也意味着完整的可索引 URL 集合在构建期就已确定——这正是 next-sitemap 能收集到它们的底层前提。
页面组件本身则通过 useRouter 读取路径参数并在标题区渲染:
const DynamicPage = () => {
const { query } = useRouter();
return (
<>
<h1>Dynamic Page</h1>
<h2>Query: {query.dynamic}</h2>
</>
);
};
从源码结构看 next-sitemap 的扫描原理
综合 index.tsx 与 [dynamic].tsx 两个文件可以推断:next-sitemap 这类构建期工具并不是靠爬取 <Link> 来发现 URL(那样会漏掉无外链入口的页面),而是直接读取 Next.js 在 next build 阶段写入产物的预渲染页面清单(pages 路由的 prefetch/预渲染数据、路由清单等元信息),把其中属于静态生成的每条路由拼接 siteUrl 后逐一落进 sitemap。因此它对「由 getStaticProps/getStaticPaths 产生的全部页面」覆盖是完整且确定性的,与页面上有没有链接指向无关。凡是需要客户端运行时渲染、无法在构建期枚举出 URL 的页面,则天然不在本方案收录范围内。
如何快速跑起本示例
官方示例的 README 提供了三种包管理器对应的引导命令,它们都会调用 packages/create-next-app 脚手架,把本示例目录的内容复制成一个可直接运行的新项目:
npx create-next-app --example with-next-sitemap with-next-sitemap-app
yarn create next-app --example with-next-sitemap with-next-sitemap-app
pnpm create next-app --example with-next-sitemap with-next-sitemap-app
启动后按上文流程运行:
npm install # 安装依赖(含 next-sitemap@3.1.22)
npm run dev # 开发模式调试页面
npm run build # 生产构建,结束后自动执行 postbuild: next-sitemap
npm run start # 启动生产服务器
执行 npm run build 后,可以按 next-sitemap 的工具约定检查构建输出目录(站点静态资源根目录)中是否已生成按 Sitemaps 协议组织的站点地图文件与 robots.txt;站点地图中应能同时看到 / 以及 /page-0 … /page-9999 等路径。正式上线前,务必把 siteUrl 从 https://example.com 改为实际域名后再重新构建,保证 XML 中的 <loc> 为绝对可访问地址。
需要说明的运行前提:本示例基于 pages router 与 getStaticProps/getStaticPaths 静态生成模型,若你的项目已改用 App Router,则 sitemap 生成机制的接入点完全不同(详见下文对比)。另外 next 依赖在示例中声明为 latest,实际安装到的版本以安装时为准。
超大站点场景:自动拆分与 robots 聚合
示例 README 明确指出 next-sitemap 的核心能力之一是"支持将大型 sitemap 拆分成多个文件"。由于 Sitemaps 协议对单个文件可容纳的 URL 条数存在上限(业界以 50000 条为通用红线,仓库文档中亦以此为注释依据),当站点页面量级很大时,单文件站点地图会导致搜索引擎拒绝或截断解析。
next-sitemap 的做法是自动按体积阈值将 URL 列表切分为多个子文件,并生成一个 sitemap 索引文件,最终由索引文件统一指向各子文件,从而突破单文件条数限制;同时 robots.txt 里声明的 sitemap 指向即索引文件本身。示例配置中的 robotsTxtOptions.additionalSitemaps 则在"子文件切分"之外提供了另一类聚合途径:把托管在别处、由 next-sitemap 之外的流程维护的 sitemap 也追加进 robots 声明,实现整个站点多份 sitemap 的集中注册。这两项机制配合,构成了大中型站点"站点地图自动更新 + 统一入口"的完整闭环。
与 App Router 原生方案对照:何时用哪种
本示例讲解的是 pages router 时代最成熟的第三方方案。而在当前仓库针对 App Router 的官方文档中,sitemap 已有一等公民的框架原生支持:只需在 app 目录下放置 sitemap.(xml|js|ts) 文件,导出默认函数返回 URL 数组即可,Next.js 会按元数据文件约定自动对外提供 /sitemap.xml。两种方案各有明确适用边界:
- pages router 项目(本示例场景):框架本身不提供原生 sitemap 文件约定,
next-sitemap作为构建后处理工具是事实标准选择,同时还免费获得robots.txt生成与超大 sitemap 自动拆分两项能力。 - App Router 项目:应优先采用 App Router 的 sitemap 文件约定,它支持
lastModified、changeFrequency、priority、多语言alternates、图片/视频 sitemap,以及通过generateSitemaps函数在单个 sitemap 内动态拆分为/sitemap/[id].xml的多文件输出。这类文件是特殊的 Route Handler,默认按静态内容缓存,可在构建期或请求期动态组装 URL。
因此选型结论可以概括为:路由体系决定方案——pages router 用本示例的 next-sitemap 构建钩子方案;App Router 用原生 sitemap.ts 文件约定;两者解决的问题相同,但接入位置(构建后处理 vs 元数据文件约定)与能力模型不同。
小结
通过 with-next-sitemap 这一示例,我们可以完整提炼出在 Next.js(pages router)中落地自动化 SEO 基础设施的三条实践要点:
- 配置即声明:一个 next-sitemap.config.js 文件同时承载
siteUrl、generateRobotsTxt与robotsTxtOptions三个维度的声明,多份 sitemap 的注册与 robots 引用无需人工维护。 - 钩子即自动化:
package.json中postbuild: "next-sitemap"让站点地图与每次生产构建天然同步,杜绝了"发版后忘了重新生成 sitemap"这一类运营事故。 - 静态生成是前提:只有能在构建期被确定性枚举的页面(静态页 +
getStaticProps/getStaticPaths产出的页面)才会被收录,示例用 10000 条动态路径验证了这一模型的覆盖能力;若追求框架原生能力或处于 App Router 体系,则应切换到 sitemap 文件约定 实现同等目标。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00