盖茨比:多种内容类型

Posted

技术标签:

【中文标题】盖茨比:多种内容类型【英文标题】:Gatsby: Multiple Content Types 【发布时间】:2018-10-18 22:18:37 【问题描述】:

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

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

博文内容类型

---
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 中做一些骇人听闻的事情:

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

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

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

【问题讨论】:

【参考方案1】:

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 中进行过滤,请添加到此答案中!

【讨论】:

【参考方案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
        
      
    
  

【讨论】:

以上是关于盖茨比:多种内容类型的主要内容,如果未能解决你的问题,请参考以下文章

无法读取未定义的属性(读取“道具”)-盖茨比网站上的富文本

盖茨比内容丰富的嵌入图像

javascript 盖茨比/内容丰富的菜单组件

不显示内容丰富的文本图像的盖茨比

搜索多种内容类型

在 Spring-MVC 控制器中支持多种内容类型