创建嵌套文件节点 Gatsby 4

Create nested file nodes Gatsby 4

由于 Gatsby 4 不接受在 createResolvers API 内 gatsby-node.js 内创建 remoteFileNodes,我正在寻找另一种解决方案来从我们的远程创建文件(graphql ) 来源。

在对象的上层创建文件工作得很好,但是我找不到在我的架构中的嵌套对象内创建这些文件的方法。

尽管在 Sections 中使用提供的名称创建了一个 File 对象,但其中的所有数据都会导致 null。给定的 URL 已检查且有效。

以下代码在我的 gatsby-node.js 文件中:

源节点

exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => {
  const { createNode } = actions;

  const { data } = await client.query({
    query: gql`
      query {
        
        PageContent {
          id
          main_image_url
          blocks {
            title
            sections {
              title
              nested_image_url
            }
          }
        }
      }
    `,
  });

  data.PageContent.forEach((pageContent) => {
    createNode({
      ...pageContent,
      id: createNodeId(`${PAGE_CONTENT}-${pageContent.id}`),
      parent: null,
      children: [],
      internal: {
        type: PAGE_CONTENT,
        content: JSON.stringify(pageContent),
        contentDigest: createContentDigest(pageContent),
      }
    })
  });

  return;
};

onCreateNode

exports.onCreateNode = async ({
  node,
  actions: { createNode, createNodeField },
  createNodeId,
  getCache,
}) => {

  if (node.internal.type === PAGE_CONTENT) {

This works just fine

    if (node.main_image_url) {
      const fileNode = await createRemoteFileNode({
        url: node.main_image_url,
        parentNodeId: node.id,
        createNode,
        createNodeId,
        getCache,
      });
  
      if (fileNode) {
        createNodeField({ node, name: "main_image", value: fileNode.id });
      }
    }

But this won't

    if (node.blocks && node.blocks.length > 0) {
      node.blocks.map(async({ sections }) => {

        if (sections.length > 0) {

          sections.map(async(section) => {

            if (section.nested_image_url) {

              const fileNode = await createRemoteFileNode({
                url: section.nested_image_url,
                parentNodeId: node.id,
                createNode,
                createNodeId,
                getCache,
              });
  
              if (fileNode) {
                createNodeField({ node, name: "nested_image", value: fileNode.id });
              }
            }
          })
        }
      })
    }
  }
};

创建架构

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions;

  createTypes(`
    type PageContent implements Node {
      main_image: File @link(from: "fields.main_image")
      blocks: [Block]
    }

    type Block {
      sections: [Section]
    }

    type Section {
      nested_image: File @link(from: "fields.nested_image")
    }
  `);
};

如果有人知道,将不胜感激!

我遇到了同样的问题,我找到的解决方案是使用createResolvers

    exports.createResolvers = ({ createResolvers }) => {
    const resolvers = {
        HomePageValuesBannerImage: {
            bannerImageFile: {
                type: "File",
                resolve: async (source, args, context, info) => {
                    const homePage = await context.nodeModel.findRootNodeAncestor(source)
                    const imageId = homePage.fields.bannerImage
                    const imageNode = await context.nodeModel.getNodeById({
                        id: imageId,
                    })

                    return imageNode
                },
            },
        },
    }
    createResolvers(resolvers)
}

所以我需要做的第一件事就是访问我父对象上的 fields 字段,因为每当你使用 createNodeField 时,它都会创建一个字段,其中包含你在 [= 上的节点内提供的名称14=].

要访问存储在 fields 上的节点文件 ID,在我的示例中称为 bannerImage,在您的示例 nested_image 中,您首先需要父节点的引用,因此为此,我使用 context.nodeModel.findRootNodeAncestor(source) 源只是嵌套 属性 的引用。在我的例子中是 HomePageValuesBannerImage 因为我的数据是这样的:

HomePage {
 Values {
  banner {
   image
  }
 }
}

在我的架构中,横幅 属性 的类型是 HomePageValuesBannerImage。

然后你需要创建一个新字段,文档上说is better to create a new field than updating one.

我创建的字段称为 bannerImageFile,该字段内将成为文件节点。

查询我的嵌套节点的父节点后,我只提取存储在 fields 中的文件 ID,我的自定义字段名为 bannerImage

最后我进行了查询以通过其 ID 和 return 找到一个节点。

const imageNode = await context.nodeModel.getNodeById({
                        id: imageId,
                    })

我仍在寻找解决此问题的不同方法,但这是我能找到的最佳解决方案。

与此同时,我找到了一个解决方案,其中包括使用 onCreateNodecreateSchemaCustomization API 的

onCreateNode

  // Single Node

  const fileNode = await createRemoteFileNode({
     url: node.image,
     parentNodeId: node.id,
     createNode,
     createNodeId: (id) => `${node.unique_identifier_prop}-image`,
     getCache,
   });

    // Array

    await Promise.all(
      node.images.map((url, index) => (
        createRemoteFileNode({
          url: url,
          parentNodeId: node.id,
          createNode,
          createNodeId: id => `${node.unique_identifier_prop}-images-${index}`,
          getCache,
        })
      ))
    )

首先,您可以根据自己的喜好创建一个 FileNode,而不是 API 的 createNodeId 函数。我们将其替换为唯一且可检索的标识符,因此我们可以在我们的架构中找到文件节点。

createSchemaCustomization

exports.createSchemaCustomization = async({ actions, schema }) => {
  const { createTypes } = actions;

  const typeDefs = [
    schema.buildObjectType({
      name: `**target_typename**`,
      fields: {
        // Single Node
        imageFile: {
          type: 'File',
          resolve: (source, args, context, info) => {
            return context.nodeModel.getNodeById({
              id: `${source.unique_identifier_prop}-image`,
              type: 'File',
            })
          }
        },
        // Array
        imageFiles: {
          type: '[File]',
          resolve: (source, args, context, info) => {
            const images = source.images.map((img, index) => (
              context.nodeModel.getNodeById({
                id: `${source.unique_identifier_prop}-images-${index}`,
                type: 'File',
              })
            ))
            return images
          }
        },
      }
    })
  ];

  createTypes(typeDefs)
};

createSchemaCustomization 中,我们现在可以使用模式提供的 buildObjectType 函数定义我们的自定义类型,该函数在 API.

中可用

在解析器中,我们可以使用 source 参数检索节点的值,该参数包含我们的 unique_identifier_prop。现在,通过 context 参数,我们可以使用 getNodeById 函数来检索绑定到我们提供的 ID 的文件节点。最后,我们可以 return 找到的文件节点并将其附加到我们的节点。