盖茨比:多种内容类型

dvr*_*d77 5 reactjs graphql gatsby

我试图跟上Gatsby的步伐并在演示中取得巨大成功,但是我遇到了一个相对普遍且简单的用例,但我陷入了困境。我希望可以在Markdown中编写多种内容类型,每种类型都有不同的Frontmatter,每种类型都有不同的模板。

例如,我想要一个BlogPost内容类型和一个Project内容类型:

BlogPost内容类型

---
title: My Post
date: "2017-09-21"
---

This is my blog body
Run Code Online (Sandbox Code Playgroud)

项目内容类型

---
projectName: My Project
startDate: "2017-09-21"
endDate: "2017-10-21"
---

This is my project description
Run Code Online (Sandbox Code Playgroud)

然后要使它们在相关的模板中呈现,我不得不在gatsby-node.js使用正则表达式方面做一些令人讨厌的事情:

const components = {
  blog: `./src/templates/blog-post.js`,
  projects: `./src/templates/project-post.js`,
}
exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators
  RE_DIR = new RegExp("\/pages\/([a-z]+)\/.*\.md$");
  return new Promise((resolve, reject) => {
    graphql(`
      {
        allMarkdownRemark {
          edges {
            node {
              fileAbsolutePath
              fields {
                slug
              }
            }
          }
        }
      }
    `).then(result => {
      result.data.allMarkdownRemark.edges.forEach(({ node }) => {
        // console.log(RE_DIR.exec(node.fileAbsolutePath))


        const postType = RE_DIR.exec(node.fileAbsolutePath)[1]

        if (postType) {
          createPage({
            path: node.fields.slug,
            component: path.resolve(components[postType]),
            context: {
              // Data passed to context is available in page queries as GraphQL variables.
              slug: node.fields.slug,
            },
          })
        }


      })
      resolve()
    })
  })
};
Run Code Online (Sandbox Code Playgroud)

我现在遇到的问题是,由于前题不一致,因此GraphQL似乎仅从其中一个来源中选择了前题架构。

有更简单的方法来拥有多个内容类型吗?

wes*_*bos 8

添加我基于@nicokant 的答案,但似乎有所改变。我也在这里使用 mdx 但MarkdownRemark如果这是你使用的,请换掉:

给每个源一个名称选项:

{
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/posts`,
        name: 'post',
      },
},
Run Code Online (Sandbox Code Playgroud)

然后在创建节点时,为其分配一个自定义字段:

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark` || node.internal.type === `Mdx`) {
    createNodeField({
      name: `collection`,
      node,
      value: getNode(node.parent).sourceInstanceName
    });
  })
};
Run Code Online (Sandbox Code Playgroud)

然后您可以根据自定义字段查询它:

query {
  allMdx(filter: { fields: { collection: { eq: "post"}}}) {
    edges {
      node {
        fields {
          collection
        }
        frontmatter {
          title
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


nic*_*ant 5

在中定义不同的源gatsby-config并将内容放置在不同的目录中,例如src/projectsscr/blog-posts

{
    resolve: `gatsby-source-filesystem`,
    options: {
        name: `project`,
        path: `${__dirname}/src/project/`,
},
},
    {
    resolve: `gatsby-source-filesystem`,
    options: {
        name: `posts`,
        path: `${__dirname}/src/blog-posts/`,
    },
},
Run Code Online (Sandbox Code Playgroud)

那么您可以根据中的源名称创建字段类型 gatsby-node

exports.onCreateNode =({ node, getNode, boundActionCreators }) => {
    if (node.internal.type === 'MarkdownRemark') {
        const { createNodeField } = boundActionCreators;
        node.collection = getNode(node.parent).sourceInstanceName;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以过滤graphql查询以收集内容,并且可以基于内容类型生成特定的模板。

query postsOnly {
    allMarkdownRemark(filter: { collection: { eq: "posts" } }) {
        edges {
            node {
                id
                collection
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代码基于github问题跟踪器上的此注释

注意:您不应直接在中更改节点实例gatsby-node,而应使用createNodeField。如果您知道如何使用自定义字段在graphql中进行过滤,请添加至此答案!