这是架构重构引入的所有 2.2.0 问题的元问题。
有关我们进行重构的原因及其全部内容的详细信息,请参阅博客文章。
有关发行说明和最终更新,请参阅发行博客文章。
安装最新版本的 Gatsby 并尝试运行您的站点。 希望这一切都会奏效。 如果需要,您还可以尝试两个新的 API( createTypes
和createResolvers
)。
yarn add gatsby
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
exports.sourceNodes = ({ actions, schema }) => {
const { createTypes } = actions
createTypes([
schema.buildObjectType({
name: `CommentJson`,
fields: {
text: `String!`,
blog: {
type: `BlogJson`,
resolve(parent, args, context) {
return context.nodeModel.getNodeById({
id: parent.author,
type: `BlogJson`,
})
},
},
author: {
type: `AuthorJson`,
resolve(parent, args, context) {
return context.nodeModel.getNodeById({
id: parent.author,
type: `AuthorJson`,
})
},
},
},
interfaces: [`Node`],
}),
])
}
[email protected]
[email protected]
FilterInput
类型现在不以输出类型为前缀,减少类型的扩散[email protected]
@dontInfer(noDefaultResolvers: false)
实际有效createResolvers
解析器info.originalResolver
中,即使原始字段上没有解析器也可用[email protected]
[email protected]
ID 字段的过滤器现在需要一个 ID 作为他们以前想要一个字符串的输入。 这会中断某些查询,例如:
export const query = graphql`
query BlogPostTemplateQuery($id: String!) {
post: sanityPost(id: { eq: $id }) {
id
title
}
}
`
会报告:
error GraphQL Error Variable "$id" of type "String!" used in position expecting type "ID".
虽然更新查询以反映这一点可能更正确,但这是一个重大更改,所以我想我会报告它。
@rexxars不错的发现! 我假设我们曾经将 ID 过滤器转换为字符串。 我会恢复旧的行为。
发布了新版本。
尝试在解析器中查询架构:
exports.createResolvers = ({ createResolvers, schema }) => {
createResolvers({
MenuJson: {
someResolver: {
type: `String!`,
async resolve(source, args, context, info) {
const foo = await graphql(schema, `
{
allPageJson {
nodes {
id
}
}
}
`, {})
console.log(foo)
return 'WIP'
},
},
},
})
}
TypeError: Cannot read property 'nodeModel' of undefined
at /private/tmp/test-gatsby/node_modules/gatsby/dist/schema/resolvers.js:22:15
at /private/tmp/test-gatsby/node_modules/gatsby/dist/schema/resolvers.js:49:44
at Generator.next (<anonymous>)
[...]
@NicoleEtLui对于字段解析器中的查询,请使用context.nodeModel
上提供的方法,即您可以使用context.nodeModel.getAllNodes({ type: 'PageJson' })
或更复杂的查询,您可以使用context.nodeModel.runQuery
。 这里有一些基本的例子。
如果您需要访问架构,请注意schema
参数只是一个中间表示 - 在解析器中,您可以访问info.schema
上的最终构建架构。
@stefanprobst感谢您的快速回答以及您所做的所有出色工作!
你好!
任何处理节点之间关系的建议?
例如,文件存储在 JSON 中(没有 id 字段,假设文件名为 id):
data/comments/some-uuid.json
= { "message": "Hello", "postId": "some-post" }
data/posts/some-post.json
= { "content": "post" }
使用source-filesystem
和transformer-json
插件,这使得节点具有不可预测的ID
因为转换器使用createNodeId()
。 很难从comment
找到post
comment
。
你好 !
尝试使用gatsby-config.js
任何一个启动 gatsby 项目:
gatsby-transformer-sharp
gatsby-plugin-sharp
gatsby-plugin-manifest
会抛出:
error Plugin gatsby-transformer-sharp returned an error
Error: Cannot find module 'gatsby/dist/utils/cpu-core-count'
- loader.js:581 Function.Module._resolveFilename
internal/modules/cjs/loader.js:581:15
- loader.js:507 Function.Module._load
internal/modules/cjs/loader.js:507:25
- loader.js:637 Module.require
internal/modules/cjs/loader.js:637:17
- v8-compile-cache.js:159 require
[keemotion-corporate]/[v8-compile-cache]/v8-compile-cache.js:159:20
[...]
@NicoleEtLui请更新gatsby-plugin-manifest
和gatsby-plugin-sharp
,这是在这些包中修复的https://github.com/gatsbyjs/gatsby/pull/12332
@LoicMahieu您可以手动为节点提供 id,然后您可以通过指定fieldName___NODE
字段来建立关系。
问:这个用例适合createResolvers
吗?
我正在通过gatsby-source-graphql
使用远程 CMS,其中包括对多个远程文件的引用。 我目前正在使用createRemoteFileNode
提取这些文件。 但是,页面查询很快就会变得尴尬,因为很容易进入我需要 cms 查询的结果(在gatsby-source-graphql
数据源上)以从gatsby-source-filesystem
找出我需要哪些文件的情况
理想情况下,我想将这些远程文件节点添加/链接/加入(?)从gatsby-source-graphql
到 cms 节点。 这是createResolvers
可以帮助解决的情况吗?
@skinandbones如果我理解正确,简短的回答是“可能但可能还没有”。
我们支持从第三方架构中添加类型的扩展字段CONFIGS,因此有可能到现场解析器从CMS架构与添加到类型createResolvers
,并使用createRemoteFileNode
在解析器。 例如:
https://github.com/stefanprobst/gatsby/blob/5bbfee29b5ec38f13a3070b13de4877aaddd6483/examples/using-gatsby-source-graphql/gatsby-node.js#L56 -L71
问题是createRemoteFileNode
会触发onCreateNode
API 调用,而在字段解析器中,我们目前无法知道这些后续 API 调用何时完成并且解析器返回是安全的。 (解决此问题的一种方法可能是#12202。)因此,根据您打算对远程文件执行的具体操作,这可能会也可能不会起作用。
@LoicMahieu你有一个可以链接到的示例项目吗?
@stefanprobst是的,你理解正确,异步问题是有道理的。 您链接的示例与我期望的非常相似,因此我可以试一试,看看会发生什么。 我的计划是在页面查询中通过gatsby-transformer-sharp
运行这些文件节点。
通过sourceNodes
API(像往常一样)使用createRemoteFileNode
然后使用新 API 将这些节点链接到第 3 方模式是另一种可行的方法吗? 到目前为止,我还没有能够进入 3rd 方模式来做到这一点。
@skinandbones对不起,我应该澄清:在我挂的例子中,部分目前还没有工作正是因为这个问题,当现场解析器返回时, File
节点将被创建,但ImageSharp
节点(在触发的onCreateNode
API 调用中创建)还没有。
至于第二种方法,我会对你的发现感兴趣——应该可以使用context.nodeModel.getAllNodes({ type: 'File' })
或类似context.nodeModel.runQuery({ type: 'File', query: { filter: { name: { regex: "/^remote/" } } } })
东西在解析器中查询添加的远程File
节点context.nodeModel.runQuery({ type: 'File', query: { filter: { name: { regex: "/^remote/" } } } })
@stefanprobst
下面是一个例子:
File
的复杂查找将comments
链接到post
File
。___NODE
方式而是使用新的createResolvers
来修复它:演示嘿,我刚刚读了这篇关于模式定制的
@stefanprobst我得到了这个工作,它适用于ImageSharp
。 非常酷,并且是使用 3rd 方模式的游戏规则改变者 🎉 🎉
至于第二种方法,我会对你的发现感兴趣——应该可以使用
context.nodeModel.getAllNodes({ type: 'File' })
或类似context.nodeModel.runQuery({ type: 'File', query: { filter: { name: { regex: "/^remote/" } } } })
东西在解析器中查询添加的远程File
节点context.nodeModel.runQuery({ type: 'File', query: { filter: { name: { regex: "/^remote/" } } } })
这就是我所做的......
exports.sourceNodes = async ({ actions, store, cache, createNodeId }) => {
... do createRemoteFileNode stuff ...
}
exports.createResolvers = ({ createResolvers, schema }) => {
createResolvers({
CMS_Thing: {
thumbFile: {
type: 'File!',
async resolve(source, args, context, info) {
const data = await context.nodeModel.runQuery({
type: 'File',
query: { filter: { fields: { ThingThumb: { eq: 'true' }, thingId: { eq: source.id } } } }
})
return data[0];
}
}
}
});
}
(这显然取决于我创建具有某些字段的文件节点。)
最佳路径(对于我的用例)将能够在createResolvers
使用createRemoteFileNode
createResolvers
所以希望我们能解决这个问题。
@skinandbones非常酷! 顺便说一句,您可以在runQuery
使用firstOnly: true
runQuery
来仅获得第一个结果。
暂定目标是在下周将其合并到 master 并发布。 请发表评论并尝试:)
似乎没有生成createResolvers()
中解析的类型字段的过滤器。
例子:
post.json
: { "id": "some-post", "author": "Loic", message: "Hello" }
comment.json
: { "postId": "some-post", message: "World" }
createResolvers({
CommentsJson: {
post: {
type: `PostsJson`,
resolve (source, args, context, info) {
const allNodes = context.nodeModel.getNodeById({ id: source.postId, type: 'PostsJson' })
}
}
}
})
CommentsJsonFilterInput
类型不包含post
字段。 所以这样的查询无法工作:
{
allCommentsJson(filter: {post: {author: {eq: "foo"}}}) {
nodes {
id
}
}
}
谢谢
@LoicMahieu这是预期的行为(至少现在是这样):在createResolvers
添加的新字段将不会出现在输入过滤器中,因为createResolvers
在模式生成中最后运行。 这里推荐的方法是使用createTypes
操作定义字段类型,然后在createResolvers
扩展它 - 或者使用最近添加的buildObjectType
助手(见上文)。
抱歉,这还没有得到更好的记录 - 现在您可以直接在分支中查看 API 文档: createResolvers
和createTypes
。
@LoicMahieu这是有意为之,在所有处理之后添加解析器,旨在作为对架构进行最终调整的工具。 如果您希望它们显示在过滤器中,您应该在createTypes
添加字段。 您可以使用一种新的速记语法,请参阅顶部帖子。
编辑:哎呀,没有看到@stefanprobst已经回复了:D
感谢两位的澄清。 createResolvers
和createTypes
似乎达到了相同的目标。
真正有用的一件事是保存生成的模式。 它将允许对类型进行“快照”并确保架构将保持如我们预期的那样。
我写了一个似乎运行良好的 POC:
const { printType } = require("graphql")
const fs = require("fs-extra")
const path = require("path")
const schemaFilePath = path.join(__dirname, "./src/schema.gql")
exports.sourceNodes = async ({ actions }) => {
const { createTypes } = actions
if (await fs.exists(schemaFilePath)) {
const typeDefs = (await fs.readFile(schemaFilePath)).toString()
createTypes(typeDefs)
}
}
exports.onPostBootstrap = async ({ store }) => {
const { schema } = store.getState()
const types = ["CommentsJson", "PostsJson"]
const typeDefs = types
.map(type => printType(schema.getType(type)))
.join("\n\n")
await fs.writeFile(schemaFilePath, typeDefs + "\n")
}
有了这个,我们甚至可以删除所有数据,架构仍然如我们所愿。
演示: https :
@LoicMahieu :+1: 这样的事情是我们路线图的一部分。
@hilja新的模式定制 API 不是关于运行查询,而是关于模式生成,所以这还没有改变。 正在进行实验性工作以允许字段解析器将工作卸载到其他进程,但尚未准备就绪。
发布2.2.0-rc.1
。 很快。
对新创建的字段进行查询排序似乎有问题。
我可以通过执行以下操作来创建一个新字段:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type MyNode implements Node {
copyOfId: ID!
}
`
createTypes(typeDefs)
}
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
MyNode: {
copyOfId: {
resolve(source, args, context, info) {
return info.originalResolver(
{
...source,
copyOfId: source.id,
},
args,
context,
info,
)
},
},
},
})
}
但是如果我查询:
query {
allMyNode (sort: {fields: [copyOfId]}) {
nodes {
copyOfId
}
}
}
结果未排序并按原始顺序显示。
如果我按id
排序,当然一切都很好。
我想这与@LoicMahieu之前提到的问题相同,
PS:忘记提了……这个新的 API 太棒了!! :D 不要让我的评论误导您认为我处于悲观情绪中。 我只是想变得有用。 ;) 感谢您做的伟大工作!
@MarcCoet感谢您的测试! 这是一个已知问题 - 我们目前不为排序字段调用字段解析器,请参阅 #11368。 一旦合并,这是我们将要解决的下一件事!
哦对不起。 我没有考虑寻找setFieldsOnGraphQLNodeType
问题。 我的错。
我很高兴知道它正在处理中。
所以真的没有办法用新的 API 来解决这个问题吗? 我们必须坚持createNodeField
的旧方式吗?
我尝试使用buildObjectType
但结果相同。
exports.sourceNodes = ({ actions, schema }) => {
const { createTypes } = actions
createTypes([
schema.buildObjectType({
name: `MyNode`,
fields: {
copyOfId: {
type: `ID!`,
resolve(parent) {
return parent.id
},
},
},
interfaces: [`Node`],
}),
])
}
任何其他未记录的方法来偶然实现对新节点字段的排序?
除此之外,我只是在@infer()
指令中遇到了语法错误。 但我想这就是上述已知问题中“允许对非 SDL 类型的推理选项”的含义?!
@MarcCoet
@infer()
指令的语法错误
这对你有用吗?
createTypes('type MyNode implements Node <strong i="11">@infer</strong> { foo: Boolean }')
至于排序问题:这个问题与模式定制重构有点正交。 问题是:当我们想要对不在节点对象本身但由字段解析器添加的字段进行过滤或排序时,我们需要先调用这些解析器,以便我们拥有可用于过滤和排序的完整节点。 例如,在您的示例中,节点对象没有copyOfId
字段——为了使其可用,我们需要在过滤和排序之前调用解析器。 目前,我们只对过滤字段执行此操作,而不对排序字段执行此操作。 作为一种解决方法,您可以尝试为copyOfId
添加一个虚拟过滤器到您的查询中:
query {
allMyNode (sort: { fields: [copyOfId] }, filter: { copyOfId: { ne: null } }) {
nodes {
copyOfId
}
}
}
另请参阅此评论。
我正在尝试为 gatsby-transformer-remark 生成的 frontmatter 节点设置架构,但总是遇到此错误: Error: Schema must contain unique named types but contains multiple types named "MarkdownRemarkFrontmatter".
我的架构如下所示:
type MarkdownRemarkFrontmatter implements Node {
title: String
}
@kennedyrose感谢您的测试! 以下对您有用吗?
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
createTypes(`
type MarkdownRemarkFrontmatter {
title: String
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`)
}
只有顶级类型,即由源和转换器插件生成的节点类型(如MarkdownRemark
或ImageSharp
)应该实现 Node 接口,而不是像 frontmatter 类型这样的嵌套类型。
(虽然我们在直接定位嵌套推断类型时似乎确实有一个错误)
那个有效。 谢谢!
已发布[email protected]
。
已发布[email protected]
。 谢谢大家!
@stefanprobst
这对你有用吗?
createTypes('type MyNode implements Node <strong i="9">@infer</strong> { foo: Boolean }')
确实如此! 只是原始文章具有误导性。
我想随着适当文件的到来,迷雾会升起。 ;)
关于排序问题,非常感谢您的澄清。 这真的很有帮助。
解决方法似乎有效,所以现在是完美的。
我对 Gatsby 的新可能性感到非常兴奋。 非常感谢你们为 Gatsby 所做的工作。
想x-post gatsbyjs/gatsby#12696,特别是这个帖子
看起来文件推断/检测可能在这里略有调整? 更新到2.2.2
失败,而~2.1.0
似乎正确推断文件节点。
刚刚在尝试使用 API 创建自定义接口时发现了这一点。 在接口上使用 resolveType 函数有效,但在共享接口的对象上使用 isTypeOf 函数则无效。 我认为这归结为 schema.js 中的以下代码,当没有声明函数时,它假定 resolveType 应该是节点。 这个假设现在对于自定义接口类型是不正确的。
if (!typeComposer.getResolveType()) {
typeComposer.setResolveType(node => node.internal.type);
}
顺便说一句,很棒的工作,正好赶上我的项目!
嗨@Wolfsun是的,由于无法通过 SDL 提供resolveType
,我们提供了一个在大多数情况下都可以使用的默认值,并允许通过graphql-js
类型提供自定义的。 确实,这与isTypeOf
效果不佳。 出于好奇:是否有理由在resolveType
使用isTypeOf
resolveType
?
嗨@stefanprobst ,感谢您的解释。 在这个阶段使用 resolveType 对我来说是完全可行的,但是使用 isTypeOf 会稍微干净一些,因为我有一个包含许多实现对象的接口。 我使用数据结构来表示相当复杂的基于网格的布局,我有一个 Card 接口,以及许多实现这个接口的 CardType,它们存储在相对于它们在网格上的位置的数据结构中。 由于我事先不知道 CardType,因此需要一个接口。 如果我想为额外的卡片使用插件系统,isTypeOf 可能会很有用,但我还没有考虑这么多,它甚至可能不是一个好主意,所以改天再说吧!
为了可发现性,我链接到这个例子,也许其他人也觉得有用。 希望这没问题。
我遇到了与@kennedyrose完全相同的问题,但就我而言, @stefanprobst提供的解决方案并没有太大帮助,尽管我不确定自己在做什么,但我只是尝试了所有可能的方法来创建它schema 但它总是返回有关multiple types named...
的错误。
这是代码:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type Wordpress__PAGEAcfIntro {
title: String
content: String
}
type Wordpress__PAGEAcfThe_problem {
title: String
content: String
}
type Wordpress__PAGEAcfThe_solution {
title: String
content: String
}
type Wordpress__PAGEAcf {
Intro: Wordpress__PAGEAcfIntro
The_problem: Wordpress__PAGEAcfThe_problem
The_solution: Wordpress__PAGEAcfThe_solution
}
type Wordpress__PAGE implements Node {
acf: Wordpress__PAGEAcf
}
`;
createTypes(typeDefs);
};
起初我尝试只设置我需要的类型(前 3 个)和他们的字段,但后来我得到了Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro".
。 在寻找解决方案时,我尝试了@stefanprobst解决方案(如在我的代码中,但不确定是否正确)但没有任何运气。
此外,这只是使某些字段具有可选字符串值(如果任何字段没有标题或内容,则查询中断)的工作量很大,这只是初始实现,我可能必须这样做在整个网站中相同的更多领域也可能是可选的,所以我非常害怕这个解决方案,真的希望有更好的方法来解决它。
好吧,经过更多的挖掘和尝试之后,实际上并不知道我在做什么,我想出了这个解决问题的代码片段:
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Wordpress__PAGEAcfIntro: {
title: { type: `String` },
content: { type: `String` },
},
Wordpress__PAGEAcfThe_problem: {
title: { type: `String` },
content: { type: `String` },
},
Wordpress__PAGEAcfThe_solution: {
title: { type: `String` },
content: { type: `String` },
},
});
};
虽然我仍然不确定为什么我的第一个解决方案不起作用。 不过,这似乎更容易维护。
最后的想法是,我不确定我是否只是缺乏 Gatsby API 的知识,或者文档对这个特定问题具有误导性。 我认为应该更容易找到how to have optional fields in a graphql query using gatsby
问题的解决方案,因为在使用像 WordPress 这样的 CMS 时,这是一件非常基本的事情,您可以在其中拥有多个自定义字段,而且很可能其中很多都会是可选的。
将字段声明为文件数组对我不起作用。
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type MarkdownRemarkFrontmatter implements Node {
images: [File]
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`
createTypes(typeDefs)
}
可能与https://github.com/gatsbyjs/gatsby/issues/12696 有关
我遇到了与@kennedyrose完全相同的问题,但就我而言, @stefanprobst提供的解决方案并没有太大帮助,尽管我不确定自己在做什么,但我只是尝试了所有可能的方法来创建它schema 但它总是返回有关
multiple types named...
的错误。这是代码:
exports.sourceNodes = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` type Wordpress__PAGEAcfIntro { title: String content: String } type Wordpress__PAGEAcfThe_problem { title: String content: String } type Wordpress__PAGEAcfThe_solution { title: String content: String } type Wordpress__PAGEAcf { Intro: Wordpress__PAGEAcfIntro The_problem: Wordpress__PAGEAcfThe_problem The_solution: Wordpress__PAGEAcfThe_solution } type Wordpress__PAGE implements Node { acf: Wordpress__PAGEAcf } `; createTypes(typeDefs); };
起初我尝试只设置我需要的类型(前 3 个)和他们的字段,但后来我得到了
Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro".
。 在寻找解决方案时,我尝试了@stefanprobst解决方案(如在我的代码中,但不确定是否正确)但没有任何运气。此外,这只是使某些字段具有可选字符串值(如果任何字段没有标题或内容,则查询中断)的工作量很大,这只是初始实现,我可能必须这样做在整个网站中相同的更多领域也可能是可选的,所以我非常害怕这个解决方案,真的希望有更好的方法来解决它。
@eddiemf ,不完全确定,但我认为您可能遇到的问题是您尝试定义的类型已经从 Wordpress 数据源推断出来。 所以实际上它们被定义了两次。 使用 createResolvers 将简单地在现有类型上创建新字段,或者通过事物的外观覆盖现有字段(?)。
2.2.10
许多小修复,包括显式节点关系正常工作。
@Wolfsun是的,这正是我的想法,但我觉得文档引导您使用createTypes
作为此问题的解决方案,而实际上您应该使用createResolvers
。
正如我所说,我认为这是处理 WordPress 时的一个非常常见的问题,因此最好为此提供一个有据可查的解决方案。
@eddiemf我对 wordpress 插件不是很熟悉,但是using-wordpress
示例中的扩展类型似乎按预期工作。 如果您能够提供指向您的回购的链接,我可以看看可能是什么问题。
请注意,我们知道我们对文档仍然非常了解。 我的猜测是这个问题与哪些类型必须实现Node
接口有关——这应该主要由插件本身处理(一旦它们被移植到新的 API)。
Node
接口的语义是在 Gatsby 的内部数据存储中标记实际节点支持的类型,即插件通过createNode
操作创建的对象,并具有id
字段。 这意味着虽然Frontmatter
类型只是在MarkdownRemark
节点上定义frontmatter
字段上的形状,但我猜想 wordpress 插件实际上注册了很多顶部 -级别节点类型。
@stefanprobst我完全理解现在对文档的了解,我只是想帮忙:)
简而言之,我的应用程序中的 WordPress 页面具有类似于page -> acf -> someGroupOfFields -> actualField
。 在查询中,我将执行以下操作作为示例:
wordpressPage(slug: { eq: "home" }) {
acf {
intro {
title
content
}
}
}
类型会自动生成为类似于WordPress__PAGE -> WordPress__PAGEAcf -> WordPress__PAGEAcfIntro
。 问题是这些字段通常只是可选字段( title
和content
),所以如果没有提供这些字段之一,我的查询就会中断,因为它是根据获取的自动生成的数据。
我看不到插件自动创建这些字段的可能方法(它怎么知道?),但我可能错了。 所以我的第一个解决方案是只使用createTypes
并使用适当的字段创建这个WordPress__PAGEAcfIntro
类型,但后来我得到了提到的错误。
我会说我的类型创建和 Gatsby/源插件在获取数据后创建相同类型之间存在一些冲突,但我真的不是做出假设的最佳位置,因为我对 GraphQL 或 Gatsby API 一点经验都没有,所以我不确定事情应该如何实际运作。
但正如我所说,就目前而言,就像在我上一篇文章中一样创建解析器工作得非常好,所以我基本上是为我需要获取的所有内容创建类型,因为它们在 CMS 中始终是可选的。
您可以在此处查看我的gatsby-node.js
以了解我是如何做到的。
@eddiemf这很有趣。 您是否有“架构必须包含唯一命名类型但包含多个名为“Wordpress__PAGEAcfIntro”的类型”错误的示例? Gatsby 应该能够处理推断的覆盖类型,所以我不确定为什么您的代码不起作用。
@freiksenet我在尝试解决这个问题时
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type Wordpress__PAGEAcfIntro {
title: String
content: String
}
`;
createTypes(typeDefs);
};
title
字段是在 CMS 中设置的,但是content
是空的,所以我尝试了上面的代码片段并得到了这个唯一名称错误。
我也认为可以覆盖类型也是如此,因为这就是有关此新功能的文档和文章的内容,所以我很惊讶地发现它没有按预期工作。
我认为这与以下问题几乎相同:
我正在尝试为 gatsby-transformer-remark 生成的 frontmatter 节点设置架构,但总是遇到此错误:
Error: Schema must contain unique named types but contains multiple types named "MarkdownRemarkFrontmatter".
我的架构如下所示:
type MarkdownRemarkFrontmatter implements Node { title: String }
不同的是,对他有用的解决方案实际上对我不起作用。 但看起来implements Node
部分在这里被错误地使用,而在我的情况下它应该是正确的。
@eddiemf您需要在某处使用非节点类型来覆盖它。 所以MarkdownFrontmatter
(没有实现Node)需要在Markdown
节点中使用, Wordpress__PageAcfIntro
应该在WorpressPage中使用。 我们将添加一个更好的错误,但我们已经通过这种方式实现了这种行为,这样人们就不会意外地覆盖内联节点。
@freiksenet你的意思是像我在这里做的那样?
我遇到了与@kennedyrose完全相同的问题,但就我而言, @stefanprobst提供的解决方案并没有太大帮助,尽管我不确定自己在做什么,但我只是尝试了所有可能的方法来创建它schema 但它总是返回有关
multiple types named...
的错误。这是代码:
exports.sourceNodes = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` type Wordpress__PAGEAcfIntro { title: String content: String } type Wordpress__PAGEAcfThe_problem { title: String content: String } type Wordpress__PAGEAcfThe_solution { title: String content: String } type Wordpress__PAGEAcf { Intro: Wordpress__PAGEAcfIntro The_problem: Wordpress__PAGEAcfThe_problem The_solution: Wordpress__PAGEAcfThe_solution } type Wordpress__PAGE implements Node { acf: Wordpress__PAGEAcf } `; createTypes(typeDefs); };
起初我尝试只设置我需要的类型(前 3 个)和他们的字段,但后来我得到了
Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro".
。 在寻找解决方案时,我尝试了@stefanprobst解决方案(如在我的代码中,但不确定是否正确)但没有任何运气。此外,这只是使某些字段具有可选字符串值(如果任何字段没有标题或内容,则查询中断)的工作量很大,这只是初始实现,我可能必须这样做在整个网站中相同的更多领域也可能是可选的,所以我非常害怕这个解决方案,真的希望有更好的方法来解决它。
我试图通过设置每个可能的字段并在示例中使用它们来创建“整个类型树”或“类型模型”,但我遇到了相同的错误(有时会出现稍微不同的错误,指责其他类型的不是唯一的)。
虽然我必须承认,当我尝试这个时,我不知道自己在做什么,我只是尝试了各种可能的解决方案组合,但对我来说所有这些都失败了。
@eddiemf是否可以获取您正在使用的 wordpress 网站的网址? 我想自己测试它以找出导致错误的原因。
@freiksenet当然,网址是https://gatsbyislove.com
我将介绍部分中的title
字段留空,以便您可以对其进行检查。
您可以在https://gatsbyislove.netlify.com/看到介绍部分没有标题,但由于我创建了解析器,它可以正常工作。
@eddiemf 非常感谢! 得到错误,将调查。
大声笑,这是最有趣的错误。 所以我们不小心大写了 wordpress 类型。 它们都应该以wordpress
开头。 相反,我们将 Nodes 保持为小写,但将内部对象保持为大写。 所以这会奏效:
type Wordpress__PAGEAcfIntro {
title: String
content: String
}
type Wordpress__PAGEAcf {
Intro: Wordpress__PAGEAcfIntro
}
type wordpress__PAGE implements Node {
acf: wordpress__PAGEAcf
}
我现在正在推动修复,所以所有类型都以小写w
开头。
厉害了😄
但现在我认为,至少对于这种特定情况,使用解析器可以使代码更好地组织,因为我不需要一直声明这些嵌套字段,直到实现Node
的主要字段。
它真的更好还是我在这里没有看到什么?
无论如何,我会尝试不同的解决方案,看看哪一个最适合我。
感谢您的大力支持!
@eddiemf可以使用createResolvers
,但是您不会在filter
和sort
此类根字段的参数中获得这些字段。 如果对您来说没问题,请使用createResolvers
。
这是修复: https :
我明白了,在大多数情况下这应该不是问题,因为filter
和sort
通常是在始终填充的字段上制作的,但我会记住这一点。 再次感谢 :)
编辑:这不再发生,即使我没有更新任何东西。 我不知道发生了什么,或者是什么让我相信它不起作用; 但它现在有效......伟大的工作伙计们!
大家好,我玩过这个代码:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
createTypes(`
type MarkdownRemarkFrontmatter {
image: File // <---- could be a relative path, could be an empty string
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`)
}
我希望在查询降价备注节点时得到File
节点或null
节点。 相反,我总是得到null
...我必须手动查找文件:
createResolvers({
MarkdownRemarkFrontmatter: {
image: {
type: `File`,
resolve(src, args, context) {
const filePath = src[info.fieldName]
// find & return the file node
}
}
}
})
有没有办法让我简单地告诉 gatsby,“这将是一个文件节点,请找到它或返回 null”?
你好! 即使设置了createTypes
是否有可能出现warning There are conflicting field types in your data. GraphQL schema will omit those fields
以防止 GraphQL 省略字段?
这是来自gatsby develop
的警告:
ThumbprintToken.tokens.value.web:
- type: number
value: 1025
source: File "../packages/thumbprint-tokens/src/tokens/breakpoint.json"
- type: string
value: '4px'
source: File "../packages/thumbprint-tokens/src/tokens/border-radius.json"
这是createTypes
的用法:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type ThumbprintToken implements Node {
tokens: [ThumbprintTokenTokens!]!
}
type ThumbprintTokenTokens {
value: ThumbprintTokenTokensValue!
}
type ThumbprintTokenTokensValue {
web: String
ios: String
android: String
}
`;
createTypes(typeDefs);
};
在不使用createTypes
,GraphQL 确实省略了这些字段。 这些 JSON 文件的数据来自gatsby-source-filesystem
和gatsby-transformer-json
。 我使用了一个函数typeName
的配置gatsby-transformer-json
。
如果似乎不应该出现警告,很高兴制作一个小的复制品。
你好!
使用内置的JSON
类型时出现错误。
// gatsby-node.js
export const sourceNodes = ({ actions: { createTypes }, schema }) => {
createTypes([
schema.buildObjectType({
name: 'MyTypeName',
fields: {
id: 'ID!',
json: 'JSON!',
},
}),
])
}
发出以下错误:
success source and transform nodes — 1.550 s
error UNHANDLED REJECTION
Error: Schema must contain unique named types but contains multiple types named "JSON".
- Array.reduce
- SchemaComposer.js:122 SchemaComposer.buildSchema
[gatsby-ww]/[graphql-compose]/lib/SchemaComposer.js:122:12
- schema.js:480
[gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:480:47
- Generator.next
- new Promise
- schema.js:539 addCustomResolveFunctions
[gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:539:18
- schema.js:162
[gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:162:11
- Generator.next
这可能是graphql-compose
提供自己的JSON
类型而不是使用gatsby/graphql
版本的结果吗?
gatsby info
输出:
System:
OS: macOS 10.14.2
CPU: (4) x64 Intel(R) Core(TM) i5-7600K CPU @ 3.80GHz
Shell: 5.6.2 - /usr/local/bin/zsh
Binaries:
Node: 10.15.3 - /var/folders/3z/fgqk0pmx30l2pc4801884_sm0000gn/T/yarn--1554423671012-0.23391063288947023/node
Yarn: 1.12.3 - /var/folders/3z/fgqk0pmx30l2pc4801884_sm0000gn/T/yarn--1554423671012-0.23391063288947023/yarn
npm: 6.4.1 - ~/.n/bin/npm
Languages:
Python: 2.7.10 - /usr/bin/python
Browsers:
Chrome: 73.0.3683.86
Firefox: 64.0
Safari: 12.0.2
npmPackages:
gatsby: 2.3.11 => 2.3.11
@angeloashmore它应该通过https://github.com/gatsbyjs/gatsby/pull/13028修复,我今天会制作一个预发布版本,以便您进行测试。
@danoc目前没有办法禁用这样的警告。 使用https://github.com/gatsbyjs/gatsby/pull/13028如果您使用@dontInfer
,则不应进行示例值检查,并且不会出现警告。 但是也不会有任何推断。
@d4rekanguok你能为此提供一个小的复制品吗? 它应该像你描述的那样工作。
@samovertonjr @smurrayatwork请不要取消这个问题。 谢谢!
不知道点击会影响每个人。
已发布2.4.0-alpha.2
。
@prashant-andani Pleae 不要解开这个问题。 谢谢!
嗨,那是偶然的……抱歉
在星期二,二零一九年四月三十日在18:38,伦纳特[email protected]写道:
@prashant-andani https://github.com/prashant-andani请不要取消固定
这个问题。 谢谢!—
你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/gatsbyjs/gatsby/issues/12272#issuecomment-487944961 ,
或静音线程
https://github.com/notifications/unsubscribe-auth/AAGKROYK4RRFYRE3MOQL2NLPTBAE7ANCNFSM4G3OVU5Q
.>
问候
普拉尚·S·安达尼
映射的执行顺序是什么? 我有一组帖子,我试图将它们映射到诸如post -> authors
示例之类的类别。 我的原始源代码有编号,所以我使用创建类型来强制执行字符串假设。 不幸的是,如果我使用createTypes
,映射似乎不起作用。 我认为createTypes
在创建主模式之前运行了吗?
//gatsby-config.js
mapping: {
"MarkdownRemark.frontmatter.speaker": `AuthorsYaml.name`, // works as expected
"MarkdownRemark.frontmatter.categories": `CategoriesYaml`,
},
//gatsby-node.js
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type MarkdownRemarkFrontmatter {
categories: [String]
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`
createTypes(typeDefs)
}
查询…
{
allMarkdownRemark {
nodes {
frontmatter {
categories
speaker {
name
}
}
}
}
}
产量…
"allMarkdownRemark": {
"nodes": [
{
"frontmatter": {
"categories": [
"22"
],
"speaker": {
"name": "Sean Higgins"
}
}
}
]
我找到了一个可行的解决方案,我告诉类型期望 CategoryYaml 类型,而不是将其强制为字符串并使用自定义解析器来获取数据。
似乎有了映射机制,我可能应该能够强制进行字符串强制转换,然后使用映射为我进行连接。
也许我错过了什么?
嵌套类型:
gatsby-source-prismic
例如
PrismicNewsBody
PrismicNewsBody
PrismicNewsBodyPrimary
PrismicNewsBodyItems
类型具有可重复组的概念(最终出现在 Items 中),但如果组中没有任何内容,则查询将失败(因为您正在查询尚未推断的类型成员)。
但是,如果您定义类型以便可以声明items
,则一旦您实际使用重复组,它就会被称为重复项; 让您处于拥有 [0.. ] 条数据但只能拥有支持 0 或 1.. 的代码的状态。
那么代码(是否已经有方法)可以合并不是implements Node
吗?
下一个: Prismic 的类型系统是一个皇家 PITA,当使用切片等时,会创建名称附加到其容器名称的类型。 这是合理的,因为它的行为方式 - 它有一个“切片库”的概念,但它是一个复制库,而不是一个参考库 - 类型定义只是复制到内容类型的类型 def 中。
OTOH 程序员讨厌重复。 所以我通过在一页上定义它,将它保存到“库”并向外复制来确保给定名称的 Slice 类型在任何地方都是相同的 - 我们(我们吗?)有能力吗?添加接口而不是
query {
pageOne {
data {
body {
... on PageOneBodyMyslice {
primary {
field
}
}
}
}
}
pageTwo {
data {
body {
... on PageTwoBodyMyslice {
primary {
field
}
}
}
}
}
}
...我们可以
``
接口 MySlice {
基本的 {
场地
}
}
询问 {
第一个{
数据 {
身体 {
... 在 MySlice {
... MySliceFragment
``
@awilkins gatsby-source-prismic
作者在这里。
我们正在努力实现自动模式加载,以便 Gatsby 了解有关您的自定义类型形状的所有信息。 我们希望在本周发布一个测试版(其中还包括一个预览系统!)。
您将需要向插件提供您的架构。
回复:你关于接口的问题,这个想法是合理的,但我不确定这些类型是否合并。 所有切片都实现Node
接口并遵循pascalcase(${customType} ${sliceZoneName} ${sliceName})
命名约定。
@motleydev嗨! 所以 createTypes 和 mappings 几乎是同时运行的。 用户定义的类型总是优先于映射类型。 在这种情况下,您需要使用自定义解析器。 在这种情况下,Gatsby 无法真正知道您想要一个将被序列化为字符串的对象,因为 String 和 CategoriesYaml 不是兼容的类型。
@angeloashmore感谢您的回复! 我会期待的; 我的客户无疑会想要改变,这会让事情变得更容易。
接口
我相信您已经注意到,由于 Prismic 的工作方式,它的“切片库”只是让您将切片类型信息复制到您的自定义类型中 - 因此,您可以实际拥有的 POV 中需要不同的类型名称在不同的页面类型中具有相同名称的完全不同的切片类型。
在 CMS 中更新切片类型是一个 PITA,因为您必须在一个地方进行,然后将其复制到所有其他类型,然后打开所有内容并更新它(如果您引入了任何不兼容的更改)。
但是……如果您表现得很好并且始终如一地执行此操作(或者只是拥有一组非常有用且成熟的切片),那么能够为每种切片类型声明一个全局 GraphQL 片段或(也许? ) 即使是所有切片的一个也会很可爱 - 但片段只能应用于一种类型或接口,因此希望将通用接口分配给不同页面上具有相同名称的不同但相同的切片类型。
已发布[email protected]
。
大家好。 我已经更新到 Gatsby 2.5.0
但似乎遇到了与@angeloashmore相同的类型冲突, graphql-compose和gatsby之间的 JSON 类型。 有什么简单的方法可以解决这个冲突吗?
如果有帮助,我将从 Gatsby 1.9.x 升级。 日志如下:
``
错误未处理的拒绝
错误:架构必须包含唯一命名的类型,但包含多个名为“JSON”的类型。
Array.reduce
Array.reduce
SchemaComposer.js:130 SchemaComposer.buildSchema
[博客]/[graphql-compose]/lib/SchemaComposer.js:130:12
schema.js:500
[博客]/[gatsby]/dist/schema/schema.js:500:47
生成器.next
debuggability.js:313 Promise._execute
[npm]/[gatsby-cli]/[bluebird]/js/release/debuggability.js:313:9
promise.js:483 Promise._resolveFromExecutor
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:483:18
promise.js:79 新承诺
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:79:10
schema.js:559 addCustomResolveFunctions
[博客]/[gatsby]/dist/schema/schema.js:559:18
schema.js:163
[博客]/[gatsby]/dist/schema/schema.js:163:11
生成器.next
util.js:16 tryCatcher
[npm]/[gatsby-cli]/[bluebird]/js/release/util.js:16:23
promise.js:512 Promise._settlePromiseFromHandler
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:512:31
promise.js:569 Promise._settlePromise
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:569:18
promise.js:606 Promise._settlePromiseCtx
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:606:10
async.js:142 _drainQueueStep
[npm]/[gatsby-cli]/[bluebird]/js/release/async.js:142:12
````
@Spiderpig86升级到 2.4 时有这个问题吗? 我想知道您是否可以提供一个复制项目(或您的应用程序的代码)。
最后,我最终废弃了我拥有的所有依赖项并完全重新安装了所有依赖项。 这是我现在使用的配置,效果很好。
我们遇到了gatsby-source-prismic
v3.0.0-alpha.2 和gatsby-source-filesystem
文件节点的问题。
我们告诉盖茨比图像领域将有localFile
型字段File
,但如果没有File
在网站的任何地方创建节点,盖茨比不知道File
是。
Error: Type with name "File" does not exists
抱歉,这可能是一个gatsby-source-filesystem
问题,而不是架构定制问题,但只是想知道是否有一种方法可以可靠地告诉 Gatsby File
是什么。 gatsby-source-filesystem
是否需要从源插件可以显式提供给 Gatsby 的包中导出文件类型定义?
相关问题: https :
@angeloashmore我们可以让gatsby-source-filesystem
显式注册File
类型(并且在配置的路径不存在时使它不是panic
)。 这样就可以只在gatsby-config
提供gatsby-source-filesystem
(不带选项),并在模式中提供File
类型。 在你的情况下,这样的事情会起作用吗? 这仍然需要安装gatsby-source-filesystem
,因为它拥有该类型——但目前还没有具体的计划可能会在某个时候将File
提升为核心类型。
@stefanprobst是的,类似的东西看起来可以工作。
关于插件作者,如果插件不确定地创建了一个 File 节点,这意味着:
gatsby-source-filesystem
到他们的gatsby-config.js
以确保 Gatsby 知道File
类型,或者File
节点,则插件作者仅在类型定义中包含使用File
类型的字段。 即,如果我们知道将不会使用File
字段创建节点,则不要在使用它的节点上包含File
字段。 如果查询包含现在不存在的字段,这可能会破坏构建。使用选项 1,如果用户不提供路径,则用户可以在每个develop
或build
上看到不存在的路径错误消息。 在某些项目中,除了提供File
类型之外,可能不需要使用gatsby-source-filesystem
。 也许我们可以更改它,以便它仅在提供路径的情况下检查路径是否存在?
使用选项 2,插件作者需要处理跟踪File
节点创建的复杂性增加。 这可能就像更新全局变量一样简单,但仍然需要考虑。
如果gatsby-source-filesystem
导出File
类型(通过 GraphQL 对象或 SDL 字符串)并允许插件作者使用createType
注册它,则用户不需要更改他们的工作流程和插件作者不需要跟踪File
使用情况。
如果/当File
类型更改并且插件使用具有不兼容的File
定义的不同gatsby-source-filesystem
版本时,这可能会导致将来出现问题。 这现在可以正常工作了,因为据我所知,Gatsby 综合推断了形状。
作为参考,这是我们使用File
定义字段的地方: standardTypes.graphql 。 这会直接传递给createTypes
。
如果我错了,请纠正我@stefanprobst ,但我认为将File
设为核心类型不会是一个重大变化。 它只会打破过去失败的情况,因为File
不在那里。 所以我建议我们这样做。
很抱歉把这个放在这里,如果你能引导我朝着正确的方向前进,我会提交一份更有针对性的票。
tl; dr Frontmatter 驱动的类型。
我来自 CMS 背景,因此控制我的模式很有吸引力。 我的 Gatsby 站点在 YAML 中使用带有type: author
Markdown frontmatter 来指定“类型”,但由于一切都是MarkdownRemark
节点类型,因此我没有得到真正的模式。
我现在通过createTypes
有一个Author
类型。 我尝试了多种方法来创建Author
节点,最好是作为MarkdownRemark
节点的子节点(因此它会被免费删除),但我找不到办法所以。 createNode
在解析器中似乎不可用。
@pauleveritt在字段之间设置外键关系的一种方法是使用@link
指令。 对于典型的博客(帖子为.md
文件、作者信息和.yaml
文件中的标签),它可能如下所示:
exports.sourceNodes = ({ actions }) => {
actions.createTypes(`
type MarkdownRemark implements Node <strong i="10">@dontInfer</strong> {
frontmatter: Frontmatter
}
type Frontmatter {
title: String!
author: AuthorYaml @link(by: "email")
tags: [TagYaml] @link(by: "slug")
}
type AuthorYaml implements Node <strong i="11">@dontInfer</strong> {
name: String!
email: String!
info: String
posts: [MarkdownRemark] @link(by: "frontmatter.author.email", from: "email")
}
type TagYaml implements Node <strong i="12">@dontInfer</strong> {
slug: String!
title: String!
description: String
posts: [MarkdownRemark] @link(by: "frontmatter.tags.slug", from: "slug")
}
`)
}
我们也终于有了在架构定制的API有点文档这里。 如果有任何不清楚或遗漏的地方,请告诉我们。
@freiksenet我认为这取决于是否意味着将File
的类型定义移动到核心,或者现在gatsby-source-filesystem
(部分)是否也应该随之移动。 我认为单独移动File
应该没问题。
@stefanprobst 简洁的概念......但我认为挑战就在这里:
我不知道如何根据来自现有gatsby-source-filesystem
和gatsby-transformer-remark
的frontmatter 将节点创建为AuthorYaml
gatsby-transformer-remark
。
我可能需要停止将链接目标视为 Markdown 内容并使用.yaml
gatsby-transformer-yaml 来命名节点类型。
@pauleveritt
使用
.yaml
gatsby-transformer-yaml
是的,这就是我在链接示例中所做的。 有什么理由将作者信息放在 Markdown 文件中?
@stefanprobst “有什么理由将作者信息放在
我希望一切——作者、类别、标签等——都成为一种丰富的“资源”,人们可以在 Markdown 中编辑、添加图像、代码块、MDX 内容等。
但我不会轻易得到那个。 :) 我会为那些切换到 YAML。 唉,我的“常规内容”(教程、文章、博客文章)也可以使用具有不同模式的类型,但我会坚持使用推断模式,而不是自 2.2 以来推广的显式类型/模式的新世界。
@pauleveritt是的, gatsby-transformer-remark
只会创建一个MarkdownRemark
类型 - 使用它来表示不同的实体会有问题。 所以这不是一个真正与模式相关的问题,但你需要一个 Markdown 转换器插件,它可以创建不同命名的 makrkdown 节点(这应该是非常可行的)。
也就是说(仅作为实验),可以仅使用MarkdownRemark
节点并在 frontmatter 字段上使用@link
来执行此操作。 它看起来有点难看,但它有效,请参见此处的示例。
@stefanprobst我理解你的意思,但我认为如果目标是减少推断模式和更多声明模式,Markdown frontmatter 应该在范围内。 带有 Markdown 文件的 Gatsby 是一种流行的组合。 一世
如果gatsby-transformer-remark
没有使分叉的表面积如此之大,那么在 Markdown 中拥有不同的类型/模式会更容易。 执行节点类型分配的箭头函数中有很多事情要做。
让我们结束这次谈话。 我可能是少数希望在 Markdown 中使用不同内容类型的人。 非常感谢示例代码,这就是我现在要采取的方向。
关于runQuery
及其query
参数......我有filter
正常工作,但我无法得到sort
工作的示例。 使用 sort 的测试似乎使用来自模板字符串的runQuery
。 当我尝试sort: { order: 'DESC', fields: ['frontmatter___date'] }
(或使用 'desc' 作为字符串)时,解析就失效了。
@pauleveritt它是否适用于order
上的数组?
@stefanprobst唉,不。 这个:
sort: { order: ['DESC'], fields: ['frontmatter___date'] }
...造成:
error gatsby-node.js returned an error
TypeError: Cannot read property 'resolve' of undefined
- prepare-nodes.js:34 awaitSiftField
[gatsby-theme-bulmaio]/[gatsby]/dist/redux/prepare-nodes.js:34:13
- prepare-nodes.js:52
[gatsby-theme-bulmaio]/[gatsby]/dist/redux/prepare-nodes.js:52:69
- Array.map
- prepare-nodes.js:52 resolveRecursive
[gatsby-theme-bulmaio]/[gatsby]/dist/redux/prepare-nodes.js:52:44
...
@pauleveritt不幸的是,我无法使用此基本设置进行重现——您能否为此问题提供一个小的重现? 这将非常有帮助,谢谢!
@stefanprobst找到原因:它是 2.8.x——要我提交一张新票吗?
想象一下您的gatsby-blog
用于 YAML 存储库。 将此添加到gatsby-node.js
:
exports.createResolvers = ({ createResolvers, schema }) => {
createResolvers({
Query: {
allResourcesByType: {
type: ['MarkdownRemark'],
args: {
resourceType: 'String'
},
resolve(source, args, context, info) {
return context.nodeModel.runQuery({
query: {
filter: {
frontmatter: {}
},
sort: { fields: ["frontmatter___title"], order: ["ASC"] },
},
type: `MarkdownRemark`
})
}
}
}
})
}
在 gatsby 2.7.6 中,您可以在资源管理器中查询allResourcesByType
。 在 2.8.0-2.8.2 中,您会收到解析错误。
@stefanprobst我正在尝试将我在帖子的前端指定为字符串数组的标签转换为Tag
其中包含title
和slug
字段,其中title
只是我写的字符串和slug = _.kebabCase(title)
。 我把这个片段放在一起
exports.sourceNodes = ({ actions, schema }) => {
actions.createTypes([
`type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}`,
`type Tag { title: String!, slug: String! }`,
schema.buildObjectType({
name: `MarkdownRemarkFrontmatter`,
fields: {
tags: {
type: `[Tag!]`,
resolve(source) {
if (!source.tags) return null
return source.tags.map(tag => ({
title: tag,
slug: kebabCase(tag),
}))
},
},
},
}),
])
}
这适用于将Tag
类型添加到MarkdownRemarkFrontmatter.tags
。 但是当然,当我尝试将所有标签与
tags: allMarkdownRemark {
group(field: frontmatter___tags) {
title: fieldValue
count: totalCount
}
}
我只得到我写到 frontmatter 的字符串。 我试着像这样为allTags
编写一个解析器
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
Query: {
allTags: {
type: [`Tag`],
resolve(source, args, context) {
return context.nodeModel.getAllNodes({
type: `MarkdownRemarkFrontmatterTags`,
})
},
},
},
}
createResolvers(resolvers)
}
但无法让它工作。 有什么建议吗?
@janosh
frontmatter.tags
从[String]
到[Tag]
,则field
的参数group
也将必须要么调整到frontmatter___tags___title
或frontmatter___tags___slug
。 不幸的是,这还不能正常工作,因为我们不会为group
字段调用字段解析器,仅适用于filter
和sort
字段(请参阅#11368)。{
allMarkdownRemark(filter: {frontmatter: {tags: {elemMatch: {title: {ne: null}}}}}) {
group(field: frontmatter___tags___title) {
fieldValue
totalCount
nodes {
frontmatter {
title
}
}
}
}
}
解决这个问题在我的待办事项清单上——我会尽快解决
createResolvers
片段的问题是: getAllNodes
将按类型检索节点,其中“节点”表示由源或转换器插件创建的具有唯一 ID 的对象(使用createNode
动作)。 因此,您必须检索MarkdownRemark
节点,然后在解析器中进一步操作结果。createTypes
,但可以简单地添加自定义根查询字段以按标签对帖子进行分组,并包含一个 slug 字段:// gatsby-node.js
const { kebabCase } = require(`lodash`)
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Query: {
allMarkdownRemarkGroupedByTag: {
type: [
`type MarkdownRemarkGroup {
nodes: [MarkdownRemark]
count: Int
tag: String
slug: String
}`,
],
resolve(source, args, context, info) {
const allMarkdownRemarkNodes = context.nodeModel.getAllNodes({
type: `MarkdownRemark`,
})
const groupedByTag = allMarkdownRemarkNodes.reduce((acc, node) => {
const { tags } = node.frontmatter
tags.forEach(tag => {
acc[tag] = (acc[tag] || []).concat(node)
})
return acc
}, {})
return Object.entries(groupedByTag).map(([tag, nodes]) => {
return {
nodes,
count: nodes.length,
tag,
slug: kebabCase(tag),
}
})
},
},
},
})
}
@stefanprobst感谢您的快速回复!
因此,您必须检索 MarkdownRemark 节点,然后在解析器中进一步操作结果。
我想这样做,但怀疑我忽略了一些东西,因此从错误的角度接近它。 感谢您解决此问题并计划为group
字段添加对字段解析器的支持!
也许另一种解决方案是让Tag
实现Node
这样 Gatsby 就会自动创建allTag
查询。
type Tag implements Node { title: String!, slug: String! }
然后我所要做的就是每次在调用schema.buildObjectType
for MarkdownRemarkFrontmatter
遇到一个新节点时,实际创建Tag
类型的节点。 是否可以从解析器中应用这样的副作用? 即在这种情况下检查Tag
是否存在标题MyTag
,如果不存在createNode({type: `Tag`, title: `MyTag, slug: `my-tag` })
。
@pauleveritt抱歉回复晚了!
在您的示例中,排序应该适用于:
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Query: {
allResourcesByType: {
type: ["MarkdownRemark"],
args: {
resourceType: "String",
},
resolve(source, args, context, info) {
return context.nodeModel.runQuery({
query: {
sort: { fields: ["frontmatter.post_title"], order: ["DESC"] },
},
type: "MarkdownRemark",
})
},
},
},
})
}
请注意, sort fields
和order
都是数组,并且fields
使用点符号代替三重下划线来分隔字段。 (我们必须记录下来!编辑:#14681)
在runQuery
与使用查询字符串时(即在 Graph_i_ql 资源管理器中)不同的原因有两个:
DESC
)。 我们目前没有用runQuery
(我们可能应该这样做)fields
和order
都是GraphQLEnum
字段。 在 Graph_i_ql 中,您将使用枚举键,而runQuery
需要内部枚举值。 例如fields
枚举用三重下划线分隔字段,因为 graphql 不允许使用点,但在内部这会转换为点表示法中的字段。@janosh对已解析字段的分组现在应该与[email protected]
@stefanprobst哇,真快! 感谢更新。
有没有办法在单个分组中同时获得标签的标题和 slug? 我只能弄清楚如何分组,然后只能访问其中一个。
{
tags: allMarkdownRemark {
group(field: frontmatter___tags___(slug|title)) {
(slug|title): fieldValue
count: totalCount
}
}
}
如果我尝试按frontmatter___tags
分组,
{
tags: allMarkdownRemark {
group(field: frontmatter___tags) {
tag: fieldValue
count: totalCount
}
}
}
我只得到一个结果
{
"data": {
"tags": {
"group": [
{
"tag": "[object Object]",
"count": 52
}
]
}
}
}
@janosh您只能按一个字段分组(不可能进行分层子分组)。 如果您需要title
和slug
,您可以按一个分组,并从结果中获取另一个的值(也许我误解了?):
{
allMarkdownRemark {
group(field: frontmatter___tags___title) {
fieldValue
totalCount
nodes {
frontmatter {
tags {
slug
title
}
}
}
}
}
}
@stefanprobst这不适合我的用例,但这只是一个小小的不便。 感谢您为架构定制所做的所有出色工作!
自 2.2.0 以来,我一直遇到一个问题,这似乎与操作系统有关。 我很高兴让另一个 Windows 10 用户关注它进行测试,以便我可以确认或排除它: https :
谢谢!
@laradevitt我目前无法访问 Windows 机器,而且我也不熟悉gatsby-plugin-netlify-cms-paths
- 但是如果您将frontmatter.image
上的路径替换为相对路径,它是否有效,即../static/media/gatsby-astronaut.png
?
@stefanprobst - 感谢您的回复! 是的,确实如此,但插件的重点是您不必使用相对路径:
一个 gatsby 插件,用于在使用 Netlify CMS 编辑 Markdown 文件时将 Markdown 文件中的文件路径更改为 Gatsby 友好的路径。
我创建了一个带有修复程序的拉取请求,该修复程序使返回的相对路径平台不可知。
我仍然不知道为什么它会在 2.2.0 中崩溃。 🤷♀
@laradevitt啊,对不起,应该检查自述文件。
我仍然不知道为什么它会在 2.2.0 中崩溃。
这很可能是 Gatsby 中的回归,因为 2.2.0 类型推断发生了一些变化——但在gatsby-plugin-netlify-cms-paths
规范化路径肯定看起来更正确:+1:
@stefanprobst
我刚刚创建了一个与架构定制相关的新票证。 如果我最好关闭它并将它放在这个伞线上,请告诉我。
https://github.com/gatsbyjs/gatsby/issues/16099
谢谢!
使用模式自定义时,graphQL 查询中的参数不起作用。
在观看了关于高级 GraphQL 的 Jason 流学习(由于技术困难被分成多个部分)后,我将很多讨论的内容融入到我的主题中。
但是,使用依赖于自定义架构值的 graphQL 参数(如过滤器和排序)不起作用。
在本地运行我的主题的这个分支。
启动 /___graphql 并查询所有博客帖子。
现在尝试使用按降序排序的方式再次查询 allBlogPosts。
结果:顺序没有变化(ASC 或 DESC)
查询所有帖子并显示其标题。
query MyQuery {
allBlogPost {
nodes {
title
}
}
}
结果:工作
现在查询所有带有“lorem-ipsum”标签的帖子
query MyQuery {
allBlogPost(filter: {tags: {elemMatch: {slug: {eq: "lorem-ipsum"}}}}) {
nodes {
title
}
}
}
结果:空节点数组。
尝试查询单个 BlogPost(如果没有给出参数,则默认选择第一个)。
现在尝试查询blogPost(slug: {eq: "herp-derpsum"})
。
我认为这是有效的,因为我将 slug 添加到 MdxBlogPost 节点。
https://github.com/NickyMeuleman/gatsby-theme-nicky-blog/blob/d29c966e639f4733caf9ee43e9f5755df42db71d/theme/gatsby-node.js#L209 -L210
似乎 graphql 参数使用来自 MdxBlogPost 节点的数据,而不是运行其解析器后的最终结果。 我的怀疑接近了吗?
系统:
操作系统:Linux 4.19 Ubuntu 18.04.2 LTS(仿生海狸)
CPU:(4) x64 Intel(R) Core(TM) i5-2500K CPU @ 3.30GHz
外壳:4.4.19 - /bin/bash
二进制文件:
节点:12.4.0 - /tmp/yarn--1565124765846-0.45931526383359134/node
纱线:1.16.0 - /tmp/yarn--1565124765846-0.45931526383359134/yarn
npm: 6.9.0 - ~/.nvm/versions/node/v12.4.0/bin/npm
语言:
Python:2.7.15+ - /usr/bin/python
相关部分代码在主题目录的gatsby-node.js
中。
特别是createSchemaCustomization
和onCreateNode
生命周期。
我试图大量评论以显示我的过程。
@NickyMeuleman抱歉还没来得及仔细观察,但您似乎在 BlogPost 界面上缺少链接扩展名。
您定义MdxBlogPost.tags
字段以按名称链接:
tags: {
type: "[Tag]",
extensions: {
link: { by: "name" },
},
},
在 BlogPost 界面的 typedef 中,您有:
interface BlogPost <strong i="12">@nodeInterface</strong> {
tags: [Tag]
}
它是否与
interface BlogPost <strong i="16">@nodeInterface</strong> {
tags: [Tag] @link(by: "name")
}
相关:#16466
添加您的建议后,使用基于标签的filter
查询allBlogPost
确实有效! 🎉谢谢!
在未来,我是否能够从接口中删除@link
,因为标签的链接可能因实现 BlogPost 接口的类型而异? (作者的相同问题,即使将@link
移至界面级别,过滤那里也不起作用。
@NickyMeuleman
感谢您的尝试!
看完之后,我认为这是我们需要在核心中解决的问题:这两个问题都与我们在手动准备节点时使用接口的解析器这一事实有关,以便我们可以对它们运行过滤器。 相反,我们应该运行我们从接口的resolveType
获得的类型的解析器,这也是 graphql 处理选择集时发生的情况。
在https://github.com/gatsbyjs/gatsby/pull/17284合并后,我尝试删除主题中的逻辑来解决这个问题。
二手 Gatsby 版本: 2.15.14
它似乎不起作用。
https://github.com/NickyMeuleman/gatsby-theme-nicky-blog/blob/bbc782332e6938daaa2fca1b25d6df7e78f19c6c/theme/gatsby-node.js#L278 -L282
当您注释掉上面链接的行时,不再可能在 GraphQL 中对这些字段进行过滤。
LekoArts 建议我比在不和谐中更公开地提出这个问题,因为它可能是一个很好的文档主题。
我如何用 createSchemaCustomization 描述多对多关系?
我的用例如下:
@Everspace试试这个 1. 添加到gatsby-node.js
。 我没有尝试过这个,但我正在做一些类似的从自定义类型(使用节点接口)链接到图像的操作,并且它有效。 它确实依赖于链接扩展,因此您需要使用 Gatsby 分配的 ID。 我想您可以在createPages
期间将您在数据源中使用的任何 ID 映射到 Gatsby ID 吗?
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = [
schema.buildObjectType({
name: 'Store',
fields: {
products: {
type: "[Product]",
extensions: {
link: {},
},
},
},
interfaces: ['Node'],
}),
schema.buildObjectType({
name: 'Product',
fields: {
stores: {
type: "[Store]",
extensions: {
link: {},
},
},
},
interfaces: ['Node'],
}),
]
createTypes(typeDefs)
}
@NickyMeuleman你的意思是你没有得到结果或者你没有在输入对象中看到字段?
当我注释掉该链接中的date
键时,按日期排序不再有任何影响。
query MyQuery {
allBlogPost(sort: {fields: date, order: DESC}) {
nodes {
date(fromNow: true)
}
}
}
具有与顺序设置为ASC
的相同查询相同的(非空)结果。
希望没有必要,因为有一个自定义日期解析器
有没有关于如何处理来自 Contentful 的可选图像的模式自定义的示例?
Schema Customization 发布已经有一段时间了,一切都很稳定。 我想是时候关闭这个问题了🙂
令人难以置信的工作@freiksenet和@stefanoverna ❤️
伙计们,如果您遇到与架构定制相关的问题,让我们打开独立的问题。 谢谢!
最有用的评论
已发布
[email protected]
。 谢谢大家!