ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Gatsby 站点 RSS 订阅源实战:gatsby-plugin-feed 安装、定制与底层原理

Gatsby 站点 RSS 订阅源实战:gatsby-plugin-feed 安装、定制与底层原理 Gatsby 站点 RSS 订阅源实战gatsby-plugin-feed 安装、定制与底层原理【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby本指南以 Gatsby 官方文档 adding-an-rss-feed.md 为骨架结合仓库内gatsby-plugin-feed插件的真实源码、测试与示例系统讲解如何在 Gatsby 站点中接入 RSS 订阅源。读完本文你将掌握从零安装插件、用最简配置生成/rss.xml、通过 GraphQL 查询与serialize自定义 Feed 结构、按页面路径精准注入 Feed 引用、处理非 ASCII 链接编码以及为播客输出 iTunes 专属 RSS 块。什么是 RSS FeedRSSReally Simple Syndication是一种标准的 XML 文件格式用于以可订阅的方式列出网站内容。读者可以通过新闻聚合器也叫订阅阅读器feed reader订阅并持续消费你的内容例如 Feedly、RSS Feed Reader 等应用。可以把 RSS 理解为网站内容的联合分发渠道syndicated distribution channel你只需要维护一份内容源所有订阅者都能同步获取更新。在 Gatsby 中RSS 生成能力由官方插件gatsby-plugin-feed提供它位于仓库的 packages/gatsby-plugin-feed 目录底层依赖rss包来渲染最终的 XML 文档。安装 gatsby-plugin-feed在站点根目录执行以下命令安装插件npm install gatsby-plugin-feed安装完成后进入下一步把它挂载到站点的gatsby-config.js中。最简配置让插件开箱即用Gatsby 的插件配置位于 gatsby-config.js。最简单的接入方式是在siteMetadata中声明站点 URL然后把插件名加入plugins数组module.exports { siteMetadata: { siteUrl: https://www.example.com, }, plugins: [gatsby-plugin-feed], }这一配置会触发插件的默认行为其内部逻辑定义在 internals.js 的defaultOptions中顶层默认query会查询site.siteMetadata中的title、description、siteUrl并为其生成别名site_url这些字段会直接传给rss包的feedOptions默认setup函数把查询到的siteMetadata与其余选项合并构建 RSS 根对象默认feeds包含一个基于allMarkdownRemark的 Feed按frontmatter___date降序排列limit: 1000输出到rss.xml。如果内容源是 Markdown 文件通常还需要为每篇文章生成唯一标识——一般是 URL 或 slug。下面的gatsby-node.js示例使用gatsby-source-filesystem的createFilePath为每个MarkdownRemark节点创建slug字段const { createFilePath } require(gatsby-source-filesystem) exports.onCreateNode ({ node, actions, getNode }) { const { createNodeField } actions if (node.internal.type MarkdownRemark) { const value createFilePath({ node, getNode }) createNodeField({ name: slug, node, value, }) } }为什么必须执行生产构建RSS 文件只在production 模式下生成。因此运行npm run build即gatsby build后默认会在构建产物中生成/rss.xml。从源码看生成逻辑挂在onPostBuild生命周期钩子上见 gatsby-node.jsexports.onPostBuild async ({ graphql, reporter }, pluginOptions) { const options { ...defaultOptions, ...pluginOptions } const baseQuery await runQuery(graphql, options.query) for (const { ...feed } of options.feeds) { if (feed.query) { feed.query await runQuery(graphql, feed.query).then(result merge({}, baseQuery, result) ) } // ...调用 serialize 并写入 public/output } }核心调用链是先执行顶层query拿到站点元信息再对每个feeds项执行各自的query两者结果通过lodash.merge合并后传入serialize最终把每个序列化后的条目通过rssFeed.item()追加写入public/output。对应的单元测试位于 packages/gatsby-plugin-feed/src/tests/gatsby-node.js测试中验证了fs.writeFile的目标路径正是public/rss.xml。对于类似 gatsby-starter-blog 这种 Markdown 内容的基础场景以上配置已经足够。但如果你希望深度定制可以在gatsby-config.js与gatsby-node.js中编写自定义 Feed schema。什么时候需要自定义 Feed默认插件只认识allMarkdownRemark数据源以下场景下默认配置会失效内容不是 Markdown 格式插件无法感知Markdown 文件名中带有日期如2017-05-22-second-post.md默认 slug 生成的 URL 会 404需要输出多个 Feed例如按分类、按栏目拆分需要为条目附加content:encoded全文、作者等自定义字段。这些场景都可以通过gatsby-config.js与gatsby-node.js的自定义配置解决。自定义 Feed schema 的完整配置要定制插件默认输出的 Feed 结构即 schema以适配站点内容可以从下面的代码开始module.exports { plugins: [ { resolve: gatsby-plugin-feed, options: { query: { site { siteMetadata { title description siteUrl site_url: siteUrl } } } , feeds: [ { serialize: ({ query: { site, allMarkdownRemark } }) { return allMarkdownRemark.edges.map(edge { return Object.assign({}, edge.node.frontmatter, { description: edge.node.excerpt, date: edge.node.frontmatter.date, url: site.siteMetadata.siteUrl edge.node.fields.slug, guid: site.siteMetadata.siteUrl edge.node.fields.slug, custom_elements: [{ content:encoded: edge.node.html }], }) }) }, query: { allMarkdownRemark(sort: { frontmatter: { date: DESC }}) { edges { node { excerpt html fields { slug } frontmatter { title date } } } } } , output: /rss.xml, title: Your Sites RSS Feed, }, ], }, }, ], }这段配置做了三件事顶层query查询站点的title、description、siteUrlsite_url是siteUrl的 GraphQL 别名这些元信息会进入 Feed 头部feeds数组至少包含一个 Feed 对象每个对象由一条 GraphQL 查询和serialize方法组成。本例中内容来自 Markdown 文件通过allMarkdownRemark查询并带排序与字段过滤serialize返回条目数组每个条目由 frontmatter标题、日期description摘要url/guidsiteUrl拼接 slugcustom_elementscontent:encoded写入完整 HTML构成。serialize支持返回rss包itemOptions中的全部键。output 与 title 的含义outputFeed 输出文件的路径与文件名例如/rss.xmltitle订阅源显示的名称例如Your Sites RSS Feed。从源码看output会被path.join(publicPath, feed.output)拼接其中publicPath ./public且会自动mkdirp创建输出目录见 gatsby-node.js因此output也可以写成嵌套路径比如podcast/feed.xml。配置项校验规则插件在 plugin-options.js 中用 Joi 对配置做了运行时校验。feeds中每项要求键类型必填说明outputstring是XML 文件输出路径querystring是获取 Feed 条目的 GraphQL 查询titlestring是Feed 标题serializefunction是把查询结果转为 RSS 条目数组matchstring否控制哪些页面注入 Feed 引用见下文linkstring否覆盖默认由output生成的 RSS 链接顶层还接受generator默认GatsbyJS、query、setup。所有未知字段会被透传给rss包。此外插件会通过parse(query)校验query是否为合法的 GraphQL 查询非法查询会在构建期直接报错错误信息形如Invalid plugin options for gatsby-plugin-feed: query must be a valid GraphQL query.。控制 Feed 引用注入哪些页面match默认情况下每个页面的head中都会注入 Feed 的link relalternate typeapplication/rssxml引用。如果你希望只有部分页面带上 Feed 引用例如只在/blog/下的文章页注入可以为 Feed 对象添加match字段feeds: [ { serialize: /* ... */, query: /* ... */, output: /rss.xml, title: Your Sites RSS Feed, // 只在这些路径下注入 feed 引用 match: ^/blog/, }, ],match的类型是string插件会用它构造new RegExp(match)然后测试当前页面的pathname只有正则匹配成功的页面才会包含 Feed 引用。对应的注入逻辑在 gatsby-ssr.js 的onRenderBody中const links feeds .filter(({ match }) { if (typeof match string) return new RegExp(match).exec(pathname) return true }) .map(({ output, title, link }, i) { const href link || withPrefix(output.replace(/^\/?/, /)) return ( link key{gatsby-plugin-feed-${i}} relalternate typeapplication/rssxml title{title} href{href} / ) })gatsby-ssr.js 的测试用例覆盖了多 Feed 注入、match过滤、__PATH_PREFIX__路径前缀、以及link覆盖默认链接等场景。另外值得注意href会经过withPrefix处理并规范化output的前导斜杠因此 Feed 链接能正确适配设置了pathPrefix的站点若显式提供link字段则直接使用该值而不再由output推导。处理非 ASCII 链接encodeURI如果站点存在非英文非 ASCII链接RSS 中的 URL 需要预先进行 URI 编码否则可能导致链接失效。可以直接使用 JavaScript 内置的encodeURI(string)处理url字段serialize: ({ query: { site, allMarkdownRemark } }) { return allMarkdownRemark.edges.map(edge { return Object.assign({}, edge.node.frontmatter, { description: edge.node.excerpt, date: edge.node.frontmatter.date, url: encodeURI(site.siteMetadata.siteUrl edge.node.fields.slug), guid: site.siteMetadata.siteUrl edge.node.fields.slug, custom_elements: [{ content:encoded: edge.node.html }], }) }) }注意guid可以保持未编码版本url使用编码后的版本两者在标准 RSS 阅读器中通常都能被正确识别。本地验证与发布配置完成后用以下命令生成并预览 Feedgatsby build gatsby serve然后访问http://localhost:9000/rss.xml即可检查 RSS 文件中的内容与 URL 是否正确。也可以把生成的 XML 粘贴到 W3C Feed Validation ServiceW3C 官方 Feed 校验服务进行格式校验确保订阅源完全符合 RSS 规范。关于自定义固定链接custom permalinks的提示如果博客使用了自定义固定链接——比如带日期或不带日期的 URL——那么 slug 与最终页面 URL 可能不一致。此时需要同步定制gatsby-node.js中的 slug 生成逻辑确保 RSS 中的url与页面真实 URL 一致否则订阅者点击条目会跳转到 404。示例实现可参考 examples/feed/gatsby-node.js它为每个 Markdown 节点基于文件名创建带首尾斜杠的slug字段exports.onCreateNode ({ node, actions, getNode }) { const { createNodeField } actions if (node.internal.type MarkdownRemark) { const fileNode getNode(node.parent) let nodeSlug ensureSlashes( path.basename(fileNode.relativePath, path.extname(fileNode.relativePath)) ) if (nodeSlug) { createNodeField({ node, name: slug, value: nodeSlug }) } } }为播客输出 iTunes RSS 块如果正在为播客创建 RSS Feed通常需要包含 iTunes 专属的 RSS 块。它们采用itunes:author这类带命名空间的标签格式而 GraphQL 无法直接读取这种含冒号的字段名。解决办法是使用插件的setup选项在生成 RSS 对象时注入custom_namespaces与custom_elementsmodule.exports { plugins: [ { resolve: gatsby-plugin-feed, options: { query: { site { siteMetadata { title description siteUrl site_url: siteUrl } } } , setup: options ({ ...options, custom_namespaces: { itunes: http://www.itunes.com/dtds/podcast-1.0.dtd, }, custom_elements: [ { itunes:author: Michael Scott }, { itunes:explicit: clean }, ], }), feeds: [ { serialize: /* ... */, query: /* ... */, output: /podcast.xml, title: My Podcast, }, ], }, }, ], }setup是顶层选项接收合并后的 options 并返回一个新的 RSS 选项对象。从源码看onPostBuild中执行new RSS(setup(locals))见 gatsby-node.js所以setup的返回值直接决定了 RSS 文档的根级属性。每个条目item的custom_elements则可以在serialize中逐条指定例如为单集添加itunes:duration、itunes:subtitle等字段。完整可运行的参考示例仓库中的 examples/feed 是一个开箱即用的最小示例目录结构如下gatsby-config.js配置了siteMetadatatitle / description / siteUrl、gatsby-source-filesystem指向posts目录、gatsby-transformer-remark解析 Markdown以及gatsby-plugin-feedoptions 为空即使用默认 Feedgatsby-node.js基于文件名生成slug节点字段posts两个带日期的 Markdown 文章如2017-03-09-first-post.mdsrc/pages/index.js展示 Feed 引用效果的首页。由于该示例的插件 options 为空defaultOptions中的默认查询与默认 Feedoutput: rss.xml会被直接启用——这是观察零配置生成 RSS的最佳起点。运行gatsby build gatsby serve后访问/rss.xml即可看到由两篇文章生成的订阅源。更多可用选项gatsby-plugin-feed还接受若干透传给rss包的选项具体可参考插件自身的 README。例如feeds: [ { serialize: ({ query: { site, allMarkdownRemark } }) { /* 序列化逻辑 */ }, query: /* 查询语句 */, output: /rss.xml, title: Your Sites RSS Feed, // 插件专有选项 match: ^/blog/, link: https://feeds.feedburner.com/gatsby/blog, // 透传给 rss 包 feedOptions 的选项 custom_namespaces: { media: http://search.yahoo.com/mrss/, }, language: en-US, }, ],其中link会覆盖默认由output推导的 RSS 链接适合接入 FeedBurner 等第三方托管服务其余未知字段如language、custom_namespaces、copyright、ttl等都会透传给rss包的feedOptionsserialize返回的对象则支持rss包itemOptions的全部键如title、description、url、guid、date、custom_elements、categories、author等。发布后的自动更新机制Feed 配置好之后日常几乎无需再关心它每次gatsby build都会触发onPostBuild重新查询数据并覆盖生成 XML 文件因此发布一篇新文章后Feed 会随着下一次构建自动更新。这也是 Gatsby 静态站点的典型工作流——内容即数据构建即发布订阅者始终能拿到最新内容。如果后续遇到更复杂的定制需求比如按多个分类生成多个 Feed、为不同类型的内容设计不同序列化逻辑都可以基于本文的queryserializefeeds组合无限扩展若仍有疑问也可以参考仓库的 参与贡献指南 与插件测试用例从源码层面进一步理解其行为。【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表