如何获取站点地图 Gatsby 静态文件的更新/lastmod 值

How to get updated / lastmod value for static files for sitemap Gatsby

我一直在使用 Gatsby,并一直在尝试为静态页面 (src/pages) 创建一个具有 lastmod 值的 sitemap。我看到一个 运行dom 代码片段,其中有人 运行 在他的 gatsby-config.js 中查询下面的内容,并且能够得到他最后修改它们的日期。

allSitePage {
  nodes {
    path
    context {
      updated
    }
  }
}

我没能达到同样的成就。

这是我目前尝试过的方法。我假设他正在使用上下文管理器并在他的 js 文件中设置上下文,并在每次他编辑文件时手动更新上下文的值。

const Updated = React.createContext('2021-11-29')

class IndexPage extends React.Component {
  render() {
    return (
      <div>
        {/* Example */}
      </div>
    )
  }
}

/* Also tried IndexPage.contextType = Updated */
IndexPage.useContext = Updated

export default IndexPage

我再次 运行 查询,但无法传递要在 graphql 查询中看到的值。这是我 运行 在 Graphql 操场上的查询。

query MyQuery {
  allSitePage {
    nodes {
      id
      context {
        updated
      }
    }
  }
}

这就是我在 Graphql 游乐场中的整个数据结构。

创建站点地图时如何获取/设置要在 gatsby-config.js 中使用的 updated 值?

1.使用 gatsby-source-filesystem 将静态页面文件添加到您的文件系统,以便您可以查询它们。

gatsby-config.js中添加以下内容:

{
  resolve: "gatsby-source-filesystem",
  options: {
    name: "pages",
    path: "./src/pages/",
  },
},

注意:您在name 属性中使用的任何内容都将成为您在查询中过滤的内容。

2。将 gatsby-transformer-gitinfo 添加到您的项目以在最新提交的 File 字段上添加一些 git 信息。 (plugin docs)

只需在步骤 1 下声明它,如下所示:

{
  resolve: "gatsby-source-filesystem",
  options: {
    name: "pages",
    path: "./src/pages/",
  },
},
`gatsby-transformer-gitinfo`,

我们使用这个插件是因为 Gatsby 的 File 节点中的任何 modifiedTime/mtime/changeTime/ctime 字段在部署时被覆盖因为 git 不记录或保留文件时间戳元数据。

3。现在我们已经将所有必要的数据添加到 GraphQL 中,并且可以查询它以查看它的外观:

query MyQuery {
  site {
    siteMetadata {
      siteUrl
    }
  }
  allSitePage {
    nodes {
      path
    }
  }
  allFile(filter: {sourceInstanceName: {eq: "pages"}}) {
    edges {
      node {
        fields {
          gitLogLatestDate
        }
        name
      }
    }
  }
}

注意: sourceInstanceName 应等于您在步骤 1 中为 options.name 设置的值。

查询结果应如下所示:

{
  "data": {
    "site": {
      "siteMetadata": {
        "siteUrl": "https://www.example.com"
      }
    },
    "allSitePage": {
      "nodes": [
        {
          "path": "/dev-404-page/"
        },
        {
          "path": "/404/"
        },
        {
          "path": "/404.html"
        },
        {
          "path": "/contact/"
        },
        {
          "path": "/features/"
        },
        {
          "path": "/"
        },
        {
          "path": "/privacy/"
        },
        {
          "path": "/terms/"
        }
      ]
    },
    "allFile": {
      "edges": [
        {
          "node": {
            "fields": {
              "gitLogLatestDate": "2021-12-09 23:18:29 -0600"
            },
            "name": "404"
          }
        },
        {
          "node": {
            "fields": {
              "gitLogLatestDate": "2021-12-09 23:18:29 -0600"
            },
            "name": "contact"
          }
        },
        {
          "node": {
            "fields": {
              "gitLogLatestDate": "2021-12-09 23:18:29 -0600"
            },
            "name": "privacy"
          }
        },
        {
          "node": {
            "fields": {
              "gitLogLatestDate": "2021-12-07 19:11:12 -0600"
            },
            "name": "index"
          }
        },
        {
          "node": {
            "fields": {
              "gitLogLatestDate": "2021-12-09 23:18:29 -0600"
            },
            "name": "terms"
          }
        },
        {
          "node": {
            "fields": {
              "gitLogLatestDate": "2021-12-09 23:18:29 -0600"
            },
            "name": "features"
          }
        }
      ]
    }
  },
  "extensions": {}
}

4.现在让我们把它们放在一起 gatsby-config.js:

{
  resolve: "gatsby-source-filesystem",
  options: {
    name: "pages",
    path: "./src/pages/",
  },
},
`gatsby-transformer-gitinfo`,
{
  resolve: "gatsby-plugin-sitemap",
  options: {
    query: `{
      site {
        siteMetadata {
          siteUrl
        }
      }
      allSitePage {
        nodes {
          path
        }
      }
      allFile(filter: {sourceInstanceName: {eq: "pages"}}) {
        edges {
          node {
            fields {
              gitLogLatestDate
            }
            name
          }
        }
      }
    }`,
    resolvePages: ({
      allSitePage: { nodes: sitePages },
      allFile: { edges: pageFiles }
    }) => {
      return sitePages.map(page => {
        const pageFile = pageFiles.find(({ node }) => {
          const fileName = node.name === 'index' ? '/' : `/${node.name}/`;
          return page.path === fileName;
        });

        return { ...page, ...pageFile?.node?.fields }
      })
    },
    serialize: ({ path, gitLogLatestDate }) => {
      return {
        url: path,
        lastmod: gitLogLatestDate
      }
    },
    createLinkInHead: true,
  },
}

gatsby-plugin-sitemap 选项的解释:

  • query 不言自明

  • resolvePages

    • 接受query的结果,所以我们可以使用解构将allSitePageallFile nodes/edges分配给变量。
    • 通过sitePages映射(allSitePage.nodes),使用page.path找到匹配文件name
      • 如果文件 nameindex 使用 / 进行匹配,因为路径不是 /index/,否则只需将文件 name 包装在分隔符中.
    • return 包含 git 信息的合并页面对象和匹配文件对象
    • (从 resolvePages 生成的对象数组成为插件代码中的 allPages 对象)
  • serialize

    • 这个函数映射到 allPages,也就是来自 resolvePages 的页面对象数组,因此我们可以再次使用解构来获取每个页面的 pathgitLogLatestDate
    • Return 属性:
      • url:插件将使用查询中的 siteMetaData.siteUrl 并附加此处分配的任何值以生成完整的 URL.

      • lastmod:需要一个有效的时间值,并且无论传入的格式如何,总是输出一个完整的 ISO8601 字符串。

        注意:目前似乎没有办法只通过gatsby-plugin-sitemaplastmod格式化为日期。这是因为 gatsby-plugin-sitemap 在幕后使用了这个 sitemap 库,虽然该库的某些组件有一个 lastmodDateOnly 标志可以切断时间字符串,但 gatsby-plugin-sitemap 不使用他们。

  • createLinkInHead: 链接网站头部的站点地图索引

5.最后,运行 gatsby build 你应该会在 public/sitemap/sitemap-0.xml

中看到结果

(好像 gatsby-plugin-sitemap 最近切换到了这个位置,所以如果您使用的是旧版本的插件,可能会在其他地方。)

结果应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
        xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
    <url>
        <loc>https://www.example.com/contact/</loc>
        <lastmod>2021-12-10T05:18:29.000Z</lastmod>
    </url>
    <url>
        <loc>https://www.example.com/features/</loc>
        <lastmod>2021-12-10T05:18:29.000Z</lastmod>
    </url>
    <url>
        <loc>https://www.example.com/</loc>
        <lastmod>2021-12-08T01:11:12.000Z</lastmod>
    </url>
    <url>
        <loc>https://www.example.com/privacy/</loc>
        <lastmod>2021-12-10T05:18:29.000Z</lastmod>
    </url>
    <url>
        <loc>https://www.example.com/terms/</loc>
        <lastmod>2021-12-10T05:18:29.000Z</lastmod>
    </url>
</urlset>

额外的,可能有用的细节 - 我正在使用的所有版本:

"gatsby": "^4.0.0",
"gatsby-plugin-sitemap": "^5.3.0",
"gatsby-source-filesystem": "^4.3.0",
"gatsby-transformer-gitinfo": "^1.1.0",
"allSitePage": {
      "nodes": [
        {
          "path": "/signup/united-states/new-york/"
        },
        {
          "path": "/signup/united-kingdom/london/"
        }
      ]
}

如果您的项目有嵌套页面结构,请使用下面的代码。

{
  resolve: "gatsby-source-filesystem",
  options: {
    name: "pages",
    path: "./src/pages/",
  },
},
`gatsby-transformer-gitinfo`, {
  resolve: "gatsby-plugin-sitemap",
  options: {
    query: `{
      site {
        siteMetadata {
          siteUrl
        }
      }
      allSitePage {
        nodes {
          path
        }
      }
      allFile(filter: {sourceInstanceName: {eq: "pages"}}) {
        edges {
          node {
            fields {
              gitLogLatestDate
            }
            relativePath
          }
        }
      }
    }`,
    resolvePages: ({
      allSitePage: {
        nodes: sitePages
      },
      allFile: {
        edges: pageFiles
      }
    }) => {
      return sitePages.map(page => {
        const pageFile = pageFiles.find(({
          node
        }) => {
          let fileName = node.relativePath.split('.').slice(0, -1).join('.')
          fileName = fileName === 'index' ? '/' : `/${fileName.replace('/index','')}/`
          return page.path === fileName;
        });

        return { ...page, ...pageFile?.node?.fields }
      })
    },
    serialize: ({
      path,
      gitLogLatestDate
    }) => {
      return {
        url: path,
        lastmod: gitLogLatestDate
      }
    },
    createLinkInHead: true,
  },
}