创建嵌套文件节点 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,
})
我仍在寻找解决此问题的不同方法,但这是我能找到的最佳解决方案。
与此同时,我找到了一个解决方案,其中包括使用 onCreateNode
和 createSchemaCustomization
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 找到的文件节点并将其附加到我们的节点。
由于 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,
})
我仍在寻找解决此问题的不同方法,但这是我能找到的最佳解决方案。
与此同时,我找到了一个解决方案,其中包括使用 onCreateNode
和 createSchemaCustomization
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 找到的文件节点并将其附加到我们的节点。