You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js App Router中如何静态生成站点地图(Sitemap)?

Next.js App Router中如何静态生成站点地图(Sitemap)?

首先,先解答你关于sitemap.ts调用频率和函数调用消耗的核心疑问:
在Next.js App Router中,app/sitemap.ts本质是一个特殊的Route Handler,每次有请求访问/sitemap.xml时(比如搜索引擎爬虫抓取),它都会完整执行一次——包括调用getBlogPosts拉取博客数据。这确实会消耗Vercel免费计划的函数调用额度,尤其是爬虫频繁访问的话,消耗会比你预期的更快。

接下来针对你想静态生成sitemap的需求,分两种场景给出可落地的方案:


方案1:手动创建静态sitemap.xml(适合内容不常更新的场景)

你提到的直接在public文件夹放置sitemap.xml的思路完全可行,Next.js会自动暴露public文件夹下的所有静态资源,包括这个站点地图文件。

具体操作步骤:

  1. 创建public文件夹:如果你的项目里没有public目录,直接在项目根目录手动新建一个就行(和app文件夹同级)——Next.js会自动识别这个目录,不需要额外配置。
  2. 编写静态sitemap.xml:在public目录下新建sitemap.xml文件,按照sitemap官方规范编写内容,示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <!-- 首页 -->
  <url>
    <loc>https://portfolio-blog-starter.vercel.app/</loc>
    <lastmod>2024-05-20</lastmod>
  </url>
  <!-- 博客列表页 -->
  <url>
    <loc>https://portfolio-blog-starter.vercel.app/blog</loc>
    <lastmod>2024-05-20</lastmod>
  </url>
  <!-- 单个博客文章(按需添加) -->
  <url>
    <loc>https://portfolio-blog-starter.vercel.app/blog/your-first-post</loc>
    <lastmod>2024-05-15</lastmod>
  </url>
</urlset>
  1. 验证生效:部署后访问https://your-domain.com/sitemap.xml,能看到你编写的静态内容就说明成功了。此时app/sitemap.ts会被静态文件覆盖,不会再执行任何函数调用。

方案2:构建时自动生成静态sitemap.xml(适合内容有更新,但可预先生成的场景)

如果你的博客内容会更新,但可以在部署阶段预先生成所有博客链接,那么可以写一个脚本,在Next.js构建时自动生成sitemap.xml到public文件夹——既不用手动维护链接,也不会在运行时消耗函数调用额度。

具体操作步骤:

  1. 创建生成脚本:在项目根目录新建scripts/generate-sitemap.js文件,内容如下:
import { getBlogPosts } from "../app/server/actions";
import fs from "fs";
import path from "path";

const baseUrl = "https://portfolio-blog-starter.vercel.app";

async function generateSitemap() {
  // 拉取所有博客文章数据
  const { posts } = await getBlogPosts();
  
  // 拼接sitemap的XML内容
  const urlSet = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <!-- 静态路由 -->
  <url>
    <loc>${baseUrl}</loc>
    <lastmod>${new Date().toISOString().split("T")[0]}</lastmod>
  </url>
  <url>
    <loc>${baseUrl}/blog</loc>
    <lastmod>${new Date().toISOString().split("T")[0]}</lastmod>
  </url>
  <!-- 动态博客路由 -->
  ${posts.map(post => `
  <url>
    <loc>${baseUrl}/blog/${post.slug}</loc>
    <lastmod>${post.metadata.publishedAt}</lastmod>
  </url>
  `).join("")}
</urlset>`;

  // 确保public文件夹存在
  const publicDir = path.join(process.cwd(), "public");
  if (!fs.existsSync(publicDir)) {
    fs.mkdirSync(publicDir);
  }

  // 将内容写入sitemap.xml文件
  fs.writeFileSync(path.join(publicDir, "sitemap.xml"), urlSet);
}

// 执行生成逻辑,失败则抛出错误终止构建
generateSitemap().catch(err => {
  console.error("生成sitemap失败:", err);
  process.exit(1);
});
  1. 修改构建命令:在package.json中,让build命令先执行生成脚本:
{
  "scripts": {
    "prebuild": "node scripts/generate-sitemap.js",
    "build": "next build",
    // 保留其他原有脚本
  }
}
  1. 清理动态sitemap文件:删除app/sitemap.ts,避免静态文件和动态路由冲突(静态文件优先级更高,但删除更保险)。
  2. 部署验证:运行npm run build时,脚本会自动拉取博客数据并生成sitemap.xml到public文件夹,部署后访问/sitemap.xml就能看到包含所有博客链接的静态站点地图,运行时不会再触发任何函数调用。

关键注意事项:

  • 静态sitemap的唯一缺点是:如果部署后新增/修改博客内容,sitemap不会自动同步,需要重新运行构建脚本并部署才能更新。如果需要动态更新,可能要结合ISR或定时构建,但这已经超出纯静态生成的范畴了。
  • 为什么项目初始没有public文件夹?因为Next.js App Router项目默认不会自动创建public目录,你完全可以手动创建,Next.js会自动处理该目录下的所有静态资源。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 14:04:31