盖茨比:多种内容类型

时间:2018-05-08 21:26:33

标签: reactjs graphql gatsby

我试图加快Gatsby的速度,并在演示中取得了巨大的成功,但是我遇到了一个相对常见且简单的用例。我希望有多种内容类型可以在Markdown中编写,每种内容类型都有不同的Frontmatter,每种类型都有不同的模板。

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

BlogPost内容类型

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

This is my blog body

项目内容类型

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

This is my project description

然后让他们在相关模板中渲染,我必须使用正则表达式在gatsby-node.js中做一些hacky:

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()
    })
  })
};

我现在遇到的问题是,由于前端不一致,看起来GraphQL只从其中一个源获取前端模式。

是否有更简单的方法来拥有多种内容类型?

2 个答案:

答案 0 :(得分:3)

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/`,
    },
},

然后您可以根据gatsby-node

中的源名称创建字段类型
exports.onCreateNode =({ node, getNode, boundActionCreators }) => {
    if (node.internal.type === 'MarkdownRemark') {
        const { createNodeField } = boundActionCreators;
        node.collection = getNode(node.parent).sourceInstanceName;
    }
}

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

query postsOnly {
    allMarkdownRemark(filter: { collection: { eq: "posts" } }) {
        edges {
            node {
                id
                collection
            }
        }
    }
}

代码基于对github issue tracker

的评论

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

答案 1 :(得分:2)

添加我的答案,该答案基于@nicokant,但似乎有所变化。我在这里也使用mdx,但是如果您使用的是,则换成MarkdownRemark

为每个来源指定一个名称选项:

{
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/posts`,
        name: 'post',
      },
},

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

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
    });
  })
};

然后您可以基于自定义字段进行查询:

query {
  allMdx(filter: { fields: { collection: { eq: "post"}}}) {
    edges {
      node {
        fields {
          collection
        }
        frontmatter {
          title
        }
      }
    }
  }
}