【问题标题】:How to add 'slug' tag automatically in markdown files using NetlifyCMS and Gatsby?如何使用 NetlifyCMS 和 Gatsby 在 markdown 文件中自动添加“slug”标签?
【发布时间】:2021-03-24 18:14:52
【问题描述】:

代码沙盒链接here

每当我尝试使用 NetlifyCMS 发布新博客文章时,它都会说它会发布。然而,我的 Netlify 构建失败,实际上并没有实时推送任何博客文章。

这是我得到的错误:

12:44:22 PM: error Your site's "gatsby-node.js" must set the page path when creating a page.
12:44:22 PM: The page object passed to createPage:
12:44:22 PM: {
12:44:22 PM:     "path": null,
12:44:22 PM:     "component": "/opt/build/repo/src/templates/blogTemplate.js",
12:44:22 PM:     "context": {
12:44:22 PM:         "slug": null
12:44:22 PM:     }
12:44:22 PM: }
12:44:22 PM: See the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage
12:44:22 PM: not finished createPages - 0.042s

我得到这个错误的原因是当发布新帖子时,新博客帖子的降价文件不会自动添加'slug'标签。示例:

---
title: 10 of the best SEO strategies for 2021
slug: /posts/10-best-seo-strategies-2021/ <-- I had to manually add this in the markdown file. This line is completely missing when pushing new blog posts live. This is causing the site build to fail.
date: 2021-03-26T23:53:24.128Z
excerpt: >-
  In this post, we go over 10 of the best SEO strategies for 2021. If you want
  more business, read more now!
---

一旦我手动将博客文章添加为 NetlifyCMS 之外的降价文件,并添加 slug 标签并推送到 master,它就成功构建了。显然我不想每次都这样做,我希望我的网站能够从 NetlifyCMS 正常发布。

gatsby-node.js:

exports.createPages = async ({ actions, graphql, reporter }) => {
  const { createPage } = actions
  const blogPostTemplate = require.resolve(`./src/templates/blogTemplate.js`)
  const result = await graphql(`
    {
      allMarkdownRemark(
        sort: { order: DESC, fields: [frontmatter___date] }
        limit: 1000
      ) {
        edges {
          node {
            frontmatter {
              slug
            }
          }
        }
      }
    }
  `)
  // Handle errors
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.frontmatter.slug,
      component: blogPostTemplate,
      context: {
        // additional data can be passed via context
        slug: node.frontmatter.slug,
      },
    })
  })
}

GraphQL pageQuery 在我的 /src/pages/posts.js 文件中:

export const pageQuery = graphql`
  query {
    allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
      edges {
        node {
          id
          excerpt(pruneLength: 250)
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            slug
            title
          }
        }
      }
    }
  }
`

Config.yml:

backend:
  name: github
  repo: my-repo

media_folder: uploads
public_folder: /uploads

collections:
  - name: "posts"
    label: "Posts"
    folder: "posts"
    create: true
    slug: "{{slug}}"
    fields:
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Publish Date", name: "date", widget: "date" }
      - { label: "Excerpt", name: "excerpt", widget: "string" }
      - { label: "Body", name: "body", widget: "markdown" }

blogTemplate.js file:

export const pageQuery = graphql`
  query($slug: String!) {
    markdownRemark(frontmatter: { slug: { eq: $slug } }) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        slug
        title
        excerpt
      }
    }
  }
`

知道为什么会发生这种情况吗?

【问题讨论】:

    标签: node.js graphql gatsby netlify netlify-cms


    【解决方案1】:

    知道为什么会发生这种情况吗?

    好吧,您正在尝试查询 slug 字段,但从未设置过(至少在开始时)。您的 frontmatter 具有以下字段:

    • 标题
    • 发布
    • 摘录
    • 身体

    但不是slug

    标准方法是将其添加到您的config.yml

    - { name: slug, label: Slug, required: true, widget: string }
    

    添加此项,您的查询将自动运行。

    另一种方法是使用 Gatsby 中的 built-in listeners and the resolvers (Node APIs) 根据之前设置的参数生成 slug,但您需要更改查询。在您的gatsby-node.js 上添加:

    exports.onCreateNode = ({ node, actions, getNode }) => {
      const { createNodeField } = actions;
    
      if (node.internal.type === `MarkdownRemark`) {
        let value = createFilePath({ node, getNode });
    
        createNodeField({
          name: `slug`,
          node,
          value,
        });
      }
    };
    

    使用onCreateNode,您正在根据一些规则(more details)创建一个新节点。这将创建一个名为 fields 的要查询的新集合,其中包含 slug。所以你只需要像这样调整它:

    exports.createPages = async ({ actions, graphql, reporter }) => {
      const { createPage } = actions
      const blogPostTemplate = require.resolve(`./src/templates/blogTemplate.js`)
      const result = await graphql(`
        {
          allMarkdownRemark(
            sort: { order: DESC, fields: [frontmatter___date] }
            limit: 1000
          ) {
            edges {
              node {
                fields{
                  slug
                }
                frontmatter {
                  slug // not needed now
                }
              }
            }
          }
        }
      `)
      // Handle errors
      if (result.errors) {
        reporter.panicOnBuild(`Error while running GraphQL query.`)
        return
      }
      result.data.allMarkdownRemark.edges.forEach(({ node }) => {
        createPage({
          path: node.fields.slug,
          component: blogPostTemplate,
          context: {
            // additional data can be passed via context
            slug: node.frontmatter.slug,
          },
        })
      })
    }
    

    如果不深入研究更多 Node 模式,就没有“自动化”的方式来实现这一点。您只是创建一个降价文件并查询其内容。从头开始创建slug 的逻辑是什么? slug 字段应始终是必需的。

    您可以尝试更改以下内容:

    createNodeField({
      name: `slug`,
      node,
      value,
    });
    

    如果未定义slug,则根据某些逻辑添加自定义value


    主题之外的另一件事。您正在创建重复的 excerpt:

    • 您的降价中的一个(来自 Netlify 的 CMS):

      - { label: "Excerpt", name: "excerpt", widget: "string" }
      
    • 在您的 GraphQL 查询中自动创建一个。 GraphQL + Gatsby 文件系统添加了一个自定义的excerpt 字段,该字段是通过在frontmatter 之外使用pruneLength 过滤来拆分body 的内容产生的:

        export const pageQuery = graphql`
          query {
            allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
              edges {
                node {
                  id
                  excerpt(pruneLength: 250)
                  frontmatter {
                    date(formatString: "MMMM DD, YYYY")
                    slug
                    title
                  }
                }
              }
            }
          }
        `
      

    我认为您在这里混合了一些东西,我建议您只使用其中一种以避免对您的代码产生误解。

    【讨论】:

    • 将 - { name: slug, label: Slug, required: true, widget: string } 添加到我的 config.yml 中。谢谢费兰!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2021-03-04
    相关资源
    最近更新 更多