news 2026/10/11 20:23:41

Gatsby 站点地图生成全链路拆解:从一篇 Markdown 博文到 sitemap-index.xml

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Gatsby 站点地图生成全链路拆解:从一篇 Markdown 博文到 sitemap-index.xml
  • 前端
  • 静态站点
  • Web框架

【免费下载链接】gatsby

React-based framework with performance, scalability, and security built in.

项目地址:https://gitcode.com/gh_mirrors/ga/gatsby
点击查看免费下载

examples/sitemap是 Gatsby 仓库中演示站点地图(sitemap)生成插件用法的完整示例站点,而examples/sitemap/posts/2017-05-22-second-post.md正是该示例站中用于演示的两篇占位博文之一。本文以这篇博文为线索,完整追踪一条从 Markdown 文件、frontmatter 字段、GraphQL 节点、页面创建到最终被gatsby-plugin-sitemap收录进sitemap-index.xml的构建期链路;读完本文,你将掌握 Gatsby 示例站点中博文类内容的处理流程、draft 字段对页面与站点地图的实际影响,以及 sitemap 插件全部配置项背后的源码级工作原理。

一、关联文档的定位:sitemap 示例站中的第二篇博文

该文件位于 examples/sitemap/posts/2017-05-22-second-post.md,与同目录下的 2017-03-09-first-post.md 一起构成示例站的博客内容源。示例站的整体说明见 examples/sitemap/README.md:

Gatsby example site explaining how to use the sitemap generator plugin.

也就是说,这个示例站的全部目的,就是演示gatsby-plugin-sitemap插件如何把站内页面生成站点地图。而这篇博文的具体角色,是作为"被收录进站点地图的内容页"之一——它与普通页面(如/、/page-2/)一同进入allSitePage,最终出现在生成的 XML 文件中。

需要如实说明的是,文档正文是经典的 Lorem ipsum 占位文本(约 7 段、52 行),并不承载真实业务内容;它真正的技术含量集中在文件头部的 YAML frontmatter,以及该文件在示例管线中被读取、过滤、创建页面、进入站点地图的整个流程。后文将逐一拆解。

二、博文 frontmatter:title / date / draft 三个字段的实际去向

文件头部的 frontmatter 是全文的技术起点:

--- title: First Post date: "2017-03-09" draft: false ---

三个字段在本示例中的去向各不相同,需要分别核实:

  • title:被博客模板直接消费。在 template-blog-post.js 中,页面组件通过 GraphQL 查询markdownRemark.frontmatter.title,并用<h1>{frontmatter.title}</h1>渲染成页面标题。
  • date:在本示例中并未被gatsby-node.js或博客模板引用,仅由gatsby-transformer-remark解析进frontmatter供 GraphQL 查询。从源码结构看,这个字段更多是作为博客元数据的常规写法保留,示例并未使用它生成 slug 或 lastmod。
  • draft:这是影响面最大的字段。它不直接作用于站点地图插件,而是通过控制"是否创建页面"间接决定博文能否进入站点地图(详见第四节)。

另外值得注意的一个示例细节:这篇名为2017-05-22-second-post.md的文件,frontmatter 中的title写的是First Post,date与第一篇也完全相同("2017-03-09")。这是示例数据中常见的复制粘贴占位写法,并不影响演示效果——因为该示例的页面路径(slug)完全由文件名决定,与 frontmatter 无关。

三、数据管线第一站:从 posts 目录到 MarkdownRemark 节点

要让 Markdown 文件变成可查询的数据,示例在 gatsby-config.js 中挂载了两个插件:

{ resolve: `gatsby-source-filesystem`, options: { name: `posts`, path: `${__dirname}/posts`, }, }, `gatsby-transformer-remark`,
  • gatsby-source-filesystem以name: "posts"为数据源命名,把posts/目录下(含两篇博文)的所有文件注册为File节点;
  • gatsby-transformer-remark再把 Markdown 文件转换为MarkdownRemark节点,frontmatter 被解析为frontmatter字段,正文被解析为html/excerpt等字段。

经此一步,本文档(2017-05-22-second-post.md)便成为 GraphQL 数据层中一个可查询的MarkdownRemark节点,为下一阶段的页面创建做准备。依赖声明可见 examples/sitemap/package.json,其中gatsby、gatsby-plugin-sitemap、gatsby-source-filesystem、gatsby-transformer-remark均使用next版本。

四、页面创建:draft 过滤、文件名 slug 与博客模板

页面创建逻辑位于 gatsby-node.js,这是"博文是否进入站点地图"的第一道闸门。

4.1 draft 过滤决定页面是否创建

createPagesAPI 中执行的查询如下:

allMarkdownRemark( limit: 1000 filter: { frontmatter: { draft: { ne: true } } } ) { edges { node { fields { slug } } } }

查询条件frontmatter.draft ne: true的含义是"draft 不等于 true"。因此:

  • draft: false(本文档的状态)→ 节点被查询到 → 创建博客页面 → 页面进入allSitePage→ 最终出现在站点地图中;
  • draft: true→ 节点被过滤 → 不创建页面 → 该博文不会出现在站点地图中。

这是"用 draft 控制发布状态"的常见实践:未发布的草稿连页面都不存在,自然无需在站点地图中处理。limit: 1000则是查询上限,避免一次性取回过多节点。

4.2 slug 完全由文件名决定

onCreateNode钩子对每个MarkdownRemark节点生成slug字段:

nodeSlug = ensureSlashes( path.basename(fileNode.relativePath, path.extname(fileNode.relativePath)) )

即取文件名去扩展名后,由ensureSlashes保证首尾各有一个/。于是本文档的 slug 为:

2017-05-22-second-post → /2017-05-22-second-post/

随后createPage使用该 slug 作为页面路径,并以src/templates/template-blog-post.js为模板组件、把{ slug }放进页面 context:

createPage({ path: edge.node.fields.slug, component: slash(blogPostTemplate), context: { slug: edge.node.fields.slug }, })

模板再通过markdownRemark(fields: { slug: { eq: $slug } })查询并渲染html与frontmatter.title。至此,一篇博文正式成为站点的一个独立页面,其路径/2017-05-22-second-post/也进入了allSitePage。

五、sitemap 收录:gatsby-plugin-sitemap 的构建期管线

5.1 配置入口:siteUrl 与 exclude

示例在 gatsby-config.js 中这样接入插件:

siteMetadata: { title: `GatsbyJS RSS`, description: `A blog with RSS powered by GatsbyJS.`, siteUrl: `https://www.gatsbyjs.com`, }, // ... { resolve: `gatsby-plugin-sitemap`, options: { exclude: [`/secret`], }, },
  • siteMetadata.siteUrl是构造绝对 URL 的基准地址。示例首页 index.js 对此有明确提示:插件用siteMetadata.siteUrl把相对路径拼成完整域名地址。如果未配置siteUrl,插件默认的resolveSiteUrl会直接抛错(见 internals.js 中的错误提示)。
  • exclude: ["/secret"]把/secret页面排除在站点地图之外。该页面的组件 secret.js 中写着 "This page should be excluded from sitemap.xml",与配置一一对应;与之相对,page-2.js 中写着 "This page should be included in sitemap.xml"。

5.2 生产模式才生成:onPostBuild 中的默认查询与解析函数

插件在onPostBuild阶段执行(对应实现见 packages/gatsby-plugin-sitemap/src/gatsby-node.js),因此只有生产构建才会产出站点地图。插件文档明确提示:"To test your sitemap, run:gatsby build && gatsby serve"。

默认查询定义在 options-validation.js 中:

{ site { siteMetadata { siteUrl } } allSitePage { nodes { path } } }

查询结果随后依次流经四个默认解析函数(均定义在 internals.js):

  1. resolveSiteUrl:从data.site.siteMetadata.siteUrl取出站点域名,缺失则抛错;
  2. resolvePages:从data.allSitePage.nodes取出页面数组,缺失则抛错;
  3. filterPages(默认 defaultFilterPages):按excludes数组过滤页面,匹配使用minimatch的 glob 规则,并在比较前用withoutTrailingSlash去掉末尾斜杠;
  4. serialize:把每个页面对象转成站点地图条目,默认输出{ url, changefreq: 'daily', priority: 0.7 }。

onPostBuild中任何一个环节出错(查询错误、解析失败、resolvePages未返回数组、序列化异常),都会通过reporter.panic中止构建并输出[gatsby-plugin-sitemap]:前缀的错误信息。

5.3 过滤规则:自定义 exclude 与始终排除的页面

过滤由pageFilter函数完成:先对每个页面套用内置默认排除列表,再套用用户的excludes配置。默认排除列表(不可通过filterPages关闭)为:

/dev-404-page /404 /404.html /offline-plugin-app-shell-fallback

也就是说,即使你没有配置任何exclude,开发用的 404 页面、离线回退页面也绝不会出现在站点地图中。

5.4 写出产物:sitemap-index.xml 与分片规则

过滤与序列化完成后,onPostBuild调用simpleSitemapAndIndex把结果写入public目录:

  • 固定产出sitemap-index.xml(站点地图索引文件),每达到entryLimit(默认45000)条 URL 就额外生成一个sitemap-X.xml分片;本示例页面数量远低于 45000,因此只会生成sitemap-0.xml与sitemap-index.xml;
  • 每条 URL 会通过prefixPath与siteUrl拼接为绝对地址;
  • 插件还通过 SSR 钩子(见 gatsby-ssr.js)在页面<head>中注入<link rel="sitemap" type="application/xml" href="/sitemap-index.xml">(可用createLinkInHead: false关闭),便于搜索引擎自动发现。

六、这篇博文最终去哪:站点地图中的 URL 清单

综合上述链路,将本示例各页面在最终站点地图中的去留整理如下(依据:示例配置 + 插件默认过滤逻辑 + 各页面源码):

页面路径来源是否进入站点地图原因
/index.js是普通首页
/page-2/page-2.js是普通页面
/secret/secret.js否被exclude: ["/secret"]排除
/2017-03-09-first-post/第一篇博文生成的页面是draft: false,创建页面
/2017-05-22-second-post/本文档生成的页面是draft: false,创建页面
/dev-404-page/、/404/、/404.html/等Gatsby 自动生成否插件内置默认排除

可见,本文档2017-05-22-second-post.md的最终归宿,是作为绝对地址https://www.gatsbyjs.com/2017-05-22-second-post/被写入sitemap-0.xml(拼接规则由siteUrl+prefixPath决定)。这也是它作为示例素材的核心演示价值:只要draft: false且路径不在排除列表中,一篇 Markdown 博文就会自动进入站点地图,全程无需人工维护 URL 清单。

七、从 0 到 1 复现:安装、开发与生产构建

示例的脚本定义在 examples/sitemap/package.json:

"scripts": { "develop": "gatsby develop", "build": "gatsby build", "start": "npm run develop" }

在示例目录下执行:

npm install npm run develop # 开发模式,仅用于预览页面,不会生成站点地图 npm run build # 生产构建,生成 public/ 下的站点地图 npx gatsby serve # 本地预览构建产物

注意插件文档的明确提示:站点地图只在生产模式(gatsby build)下生成,开发模式下不会出现。构建后可在gatsby serve提供的本地服务中访问/sitemap-index.xml查看索引文件,进而打开分片sitemap-0.xml检查本文档对应的 URL 是否被正确收录。

八、进阶自定义与源码级验证依据

8.1 插件选项速查表

以下默认值均来自插件源码 options-validation.js(Joi 校验),可直接在gatsby-config.js中覆盖:

选项类型与默认值作用
outputstring,默认/站点地图在public中的存放目录
createLinkInHeadboolean,默认true是否在页面<head>注入指向sitemap-index.xml的<link>
entryLimitnumber,默认45000每个分片的最大 URL 数,超出则生成多个sitemap-X.xml
queryGraphQL 字符串取站点 URL 与页面列表的查询;默认取site.siteMetadata.siteUrl与allSitePage.nodes.path
excludes数组,默认[]要排除的路径,支持 minimatch glob 匹配
resolveSiteUrl函数从查询结果返回站点 URL,可同步或异步
resolvePagePath函数从页面对象返回不带域名的 URI
resolvePages函数从查询结果返回页面对象数组
filterPages函数决定页面是否排除,返回true排除、false保留
serialize函数把页面对象转成站点地图条目(url、lastmod等)

8.2 何时必须自定义 query / resolvePages / resolveSiteUrl

从options-validation.js的注释与internals.js的抛错逻辑可以明确三点触发条件:

  • 站点 URL 不来自site.siteMetadata.siteUrl时,必须提供自定义resolveSiteUrl;
  • 覆盖query后若页面 URI 不在path字段上,必须提供自定义resolvePagePath;
  • 查询结构不是allSitePage.nodes时(例如从 WordPress、Contentful 等 CMS 取内容),必须自定义resolvePages,把多数据源合并进页面数组。

excludes数组除字符串外也可放入其他数据类型,但此时必须同步自定义filterPages(默认实现对非字符串元素会抛错)。

8.3 lastmod:搜索引擎真正读取的字段

插件默认的serialize只为每条 URL 输出changefreq: "daily"和priority: 0.7——对所有页面一视同仁,没有区分重要性与更新频率。插件文档引用了 Google 官方建议:Google 忽略<priority>与<changefreq>,但会读取<lastmod>,且错误标注会让 Google 停止读取该字段。因此实践上应自定义serialize,为每条 URL 提供准确的lastmod(如来自 CMS 的modifiedGmt字段),这正是插件文档"Recommended usage"一节给出的示例做法。

8.4 测试用例如何锁定这些行为

插件行为并非仅靠文档说明,而是有单元测试背书,见 packages/gatsby-plugin-sitemap/src/tests/internals.js:

  • withoutTrailingSlash:验证/保持不变、/test/path/去掉末尾斜杠;
  • prefixPath:验证{ url: "/test/path/", siteUrl: "https://example.net", pathPrefix: "/root" }拼接为https://example.net/root/test/path/;
  • serialize:验证默认输出恰为{ url, changefreq: "daily", priority: 0.7 };
  • pageFilter:验证/404.html被默认规则剔除、自定义excludes生效,且连续多次运行结果稳定。

这些测试与本文所述"本示例中/secret被排除、本文档博文被收录"的最终结果出自同一套代码路径,可作为你在自定义配置时验证预期行为的参照。


综上,examples/sitemap/posts/2017-05-22-second-post.md虽然只是一篇占位博文,但它串起了 Gatsby 内容类站点从 Markdown 到站点地图的完整闭环:frontmatter 的draft字段控制页面是否创建,文件名决定页面路径,而gatsby-plugin-sitemap在构建期以siteMetadata.siteUrl为基准、以exclude与内置排除列表为规则,把最终页面清单序列化成分片化的sitemap-index.xml。理解了这条链路,你就可以在自己的 Gatsby 博客中精确控制每一篇博文的搜索引擎可见性。

  • 前端
  • 静态站点
  • Web框架

【免费下载链接】gatsby

React-based framework with performance, scalability, and security built in.

项目地址:https://gitcode.com/gh_mirrors/ga/gatsby
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/11 20:23:01

DB2临时表空间告急排查与调优实战指南

简介&#xff1a;这份资源是面向DB2数据库运维DBA与性能调优人员的真实案例文档&#xff0c;聚焦银行DB2系统因临时表空间TEMPSPACE1异常膨胀至10GB而引发的SQL执行变慢问题。资源包内含1个doc文件&#xff0c;约607KB&#xff0c;完整记录了从ACTIVE SESSION异常升高入手&…

作者头像 李华
网站建设 2026/10/11 20:21:51

ANSYS有限元分析从入门到实战:Workbench与APDL核心全解

简介&#xff1a;这是一份面向机械、航空航天、汽车等工业领域工程师及初学者的ANSYS有限元分析软件入门介绍PPT&#xff0c;系统梳理了这款CAE工具的核心功能、典型应用场景及基本分析流程。内容涵盖结构、热、电磁、流体与耦合场分析等主要模块&#xff0c;并介绍Mechanical、…

作者头像 李华
网站建设 2026/10/11 20:21:14

C# PDF 电子签章签名实战:坐标定位、图层透明度与批量盖章避坑指南

简介&#xff1a;这份资源是面向C#桌面开发者的PDF电子签章实践示例&#xff0c;基于WinForm框架并集成DevExpress控件库&#xff0c;用于解决在业务系统中为PDF文档添加合法电子签章、验证文档完整性与签署身份的问题。压缩包为rar格式&#xff0c;整体约68.81MB&#xff0c;包…

作者头像 李华
网站建设 2026/10/11 20:20:34

SRGAN图像超分辨率实战:从原理到TensorFlow训练避坑指南

简介&#xff1a;一套基于TensorFlow2.5与Keras实现的SRGAN超分辨率生成对抗网络项目&#xff0c;面向深度学习研究者与图像处理开发者&#xff0c;用于从低分辨率图像生成高分辨率图像&#xff0c;支持自定义数据集训练以提升特定场景的图像细节与真实感。资源包共17个文件&am…

作者头像 李华
网站建设 2026/10/11 20:20:29

数据库课程设计实战:图书馆管理信息系统表结构与事务避坑指南

简介&#xff1a;图书馆管理信息系统数据库课程设计报告&#xff0c;内容涵盖系统开发平台、数据库规划、需求分析、逻辑设计、物理设计、应用程序设计、测试与总结等完整环节&#xff0c;适合计算机相关专业学生完成课程设计或毕业设计时参考。报告以Eclipse和SQL Server 2000…

作者头像 李华
网站建设 2026/10/11 20:18:31

chrome-win.zip 去 debugger 调试包:解压即用与实战避坑

简介&#xff1a;这份资源是面向安全测试、网络攻防演练及隐私保护需求用户的定制版Chrome浏览器&#xff0c;基于谷歌Chrome核心架构修改&#xff0c;具备绕过debugger调试与反调试能力&#xff0c;适用于金融交易、敏感数据处理等对安全要求较高的场景。压缩包共95个文件&…

作者头像 李华