连接两个Gatsby节点 [英] Connecting two gatsby nodes

查看:49
本文介绍了连接两个Gatsby节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正在使用 gatsby-mdx 插件从MDX文件创建网站.我想在SitePage对象和Mdx对象之间创建关联,以便可以对SitePage边缘执行一个graphQL查询,以构建站点导航.

So, I'm using the gatsby-mdx plugin to create a site from MDX files. I want to create an association between the SitePage object and the Mdx object so that I can do one graphQL query of the SitePage edges in order to construct a site navigation.

我的大部分代码都在TypeScript中,所以如果您想知道那些类型的WTF,请忽略任何类型注释.

Much of my code is in TypeScript, so ignore any type annotations if you're wondering WTF those are.

我的第一个想法是使用 onCreateNode API,抓住MDX节点,然后使用createNodeField动作将其添加到SitePage中.一切正常,但gatsby-mdx插件向其节点添加一堆其他信息,稍后使用

My first thought was to use the onCreateNode API, grab the MDX node, and add it to the SitePage using the createNodeField action. That all works great, B-U-T the gatsby-mdx plugin adds a bunch of other info to their node later using the setFieldsOnGraphQLNodeType API (which occurs after the onCreateNode API). I want those fields (such as frontmatter and tableOfContents) to be available in later graphql queries, but they aren't using this method.

我认为我可以像gatsby-mdx扩展Mdx节点一样扩展SitePage对象.

I figured I could just extend the SitePage object the same way gatsby-mdx was extending the Mdx node.

我在这里遇到的关键问题是我不知道如何创建Mdx GraphQL节点类型.

The key problem I ran into here was that I couldn't figure out how to create the Mdx GraphQL node type.

export const setFieldsOnGraphQLNodeType = ({type, actions, getNodes}: any, pluginOptions: any) => {
    if (type.name === "SitePage") {
        const {createParentChildLink} = actions
        return new Promise((resolve) => {
            return resolve({
                "childMdx": {
                    type: new GraphQLObjectType({
                        name: 'Mdx'
                    }),
                    async resolve(sitePageNode: any) {
                        const allNodes = getNodes()
                        if (sitePageNode.component &&
                            (sitePageNode.component.endsWith(".mdx") || sitePageNode.component === DefaultLayout)
                        ) {
                            const associatedMdx = allNodes.find((mdxNode: any) =>
                                mdxNode.internal.type === 'Mdx' && mdxNode.fileAbsolutePath === sitePageNode.component
                            )
                            if (associatedMdx) {
                                console.log("Found associated MDX node", associatedMdx.id)
                                console.log("Adding it to the sitepage node", sitePageNode.id)
                                return associatedMdx
                            }
                        }
                    }
                }
            })
        })
    }
    return {}
}

我还尝试将类型简单地传递为String('Mdx'),但这也失败了.

I also tried simply passing the type as a String ('Mdx'), but that failed too.

该插件使用我试图实现这一目标...

I tried implementing that...

export const onCreateNode = ({node, actions, getNodes}: OnCreateNodeArgument) => {
    const {createParentChildLink} = actions
    const allNodes = getNodes()
    if (node.internal && node.internal.type === 'SitePage' && node.component &&
        (node.component.endsWith(".mdx") || node.component === DefaultLayout)
    ) {
        const associatedMdx = allNodes.find((mdxNode: any) =>
            mdxNode && mdxNode.internal && mdxNode.internal.type === 'Mdx' &&
                (mdxNode.fileAbsolutePath === node.component || mdxNode.fileAbsolutePath === node.context.fileAbsolutePath)
        )
        if (associatedMdx) {
            console.log("Found associated MDX node", associatedMdx.id)
            console.log("Adding it to the sitepage node as a child", node.id)
            createParentChildLink({parent: node, child: associatedMdx})
        }
    }
}

乍看起来似乎成功了,但是

At first, that appears to succeed, but the tableOfContents property that gatsby-mdx adds to the Mdx node still isn't available in a graphQL query like:

{
    allSitePage(filter: {fields: {childMdx: {id: {ne: null}}}}) {
        edges {
            node {
                path
                fields{
                    childMdx {
                        tableOfContents
                        fileAbsolutePath
                        frontmatter {
                            title
                        }
                    }
                }
                context {
                    roughFilePath
                    id
                }
            }
        }
    }
}

其他(可能不相关)信息

我是以编程方式在gatsby-node中创建一些页面 .js.

我已经看到类似使用案例的建议,以使用节点类型映射,但是自从我在SitePage& MDX对象需要一些技巧(特别是从siteMetadata中读取一些内容并进行字符串比较),我认为这不适用于我的用例.

I've seen a suggestion for similar use cases to use node type mappings, but I since my mapping between the SitePage & the MDX object requires a bit of finesse (specifically, reading some things from siteMetadata and doing a string comparison), I don't think that will work for my use case.

推荐答案

所以我终于找到了一个更好的解决方案(比我以前的尝试(将mdx节点注入页面的context中)).

So I finally found a better solution (than my previous attempt, which involves pumping mdx node into page’s context).

Gatsby有一个未记录的方法可以将节点彼此链接:

Gatsby has a undocumented method to link nodes to one another:

是的,您可以将createNodeField与尚未记录的___NODE语法一起使用,以在节点之间创建链接.

Yes, you can can use createNodeField with the not-yet-documented ___NODE syntax to create links between nodes.

因此,步骤如下:

  • createPage中,将Mdx节点的id存储到SitePage节点.
  • onCreateNode中,如果节点为SitePage,则将createNodeFieldMdx___NODE用作字段名称,并将Mdx节点的ID作为值.
  • In createPage, store the id of the Mdx node to SitePage node.
  • In onCreateNode, if node is SitePage, use createNodeField with the Mdx___NODE as field name and Mdx node's id as value.

我的gatsby-node.js:

const path = require("path")
const { createFilePath } = require("gatsby-source-filesystem")

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === "SitePage" && node.context && node.context.id) {

    createNodeField({
      name: "Mdx___NODE",
      value: node.context.id,
      node,
    })
  }

  if (node.internal.type === "Mdx") {
    const value = createFilePath({ node, getNode })
    createNodeField({
      // 1) this is the name of the field you are adding,
      name: "slug",
      // 2) this node refers to each individual MDX
      node,
      value: `/blog${value}`
    })
  }
}


exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;
  const { data, errors } = await graphql(`
    {
      allMdx {
        edges {
          node {
            id
            fields {
              slug
            }
          }
        }
      }
    }
  `)

  if (errors) throw errors
  data.allMdx.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/components/posts-page-layout.js`),
      context: { id: node.id }
    });
  });
};

结果:

希望有帮助!

这篇关于连接两个Gatsby节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆