【问题标题】:Apollo+GraphQL - Heuristic Fragment Manual MatchingApollo+GraphQL - 启发式片段手动匹配
【发布时间】:2020-04-28 14:33:17
【问题描述】:

我有一个无头 Craft CMS,它通过 Apollo 通过 GraphQL 端点将数据返回到我的 Nuxtjs 应用程序。我有一个可以返回三种不同块类型之一的字段:richTextimagepullQuote

我的 GraphQL 端点如下所示:

query($section:[String], $slug:[String]) {
    entries(section: $section, slug: $slug) {
        id,
        title,
        uri,
        ... on blog_blog_Entry{
            contentEngine{
                __typename,
                ...on contentEngine_richText_BlockType{
                    __typename,
                    id,
                    richText
                    fontColor,
                    backgroundColor
                }
                ...on contentEngine_image_BlockType{
                    __typename,
                    id,
                    backgroundColor,
                    imageWidth,
                    image {
                        id,
                        url
                    }
                }
                ...on contentEngine_pullQuote_BlockType{
                    __typename,
                    id,
                    backgroundColor,
                    fontColor,
                    quote
                }
            }
        }
    }
}

It returns data just fine,但在我的 Nuxt 组件中尝试使用它时出现此错误:

您正在使用简单(启发式)片段匹配器,但您的查询包含联合或接口类型。 Apollo Client 将无法准确映射片段。要消除此错误,请使用文档中所述的IntrospectionFragmentMatcherhttps://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher

令人气愤的是,这个文档导致了 404。我发现了一些 other GitHub tickets 引用了这个链接,所以我不确定我应该遵循什么步骤。

我想我需要做的就是教 Apollo 的内存缓存。由于我的回复没有那么复杂,我想我可以用Defining PossibleTypes manually 逃脱。

我尝试了以下方法,但我认为我不了解如何正确设置:

const cache = new InMemoryCache({
    possibleTypes: {
        contentEngine: [
            "contentEngine_richText_BlockType", 
            "contentEngine_pullQuote_BlockType", 
            "contentEngine_image_BlockType"
        ],
    },
});

解决这个问题的任何帮助都会是一个巨大的帮助。

警告:启发式片段匹配正在进行中!

【问题讨论】:

    标签: graphql nuxt.js apollo vue-apollo


    【解决方案1】:

    我自己也为此苦苦挣扎,但在@mylesthe.dev(上面的回复)直接与我交谈以提供出色的支持和一些示例之后,我想通了。因此,对于仍然像我一样挣扎的其他人,这里的代码(感谢他的工作)最终让事情对我有用:

    首先,在你的 nuxt.config.js 中设置你的 apollo 配置:

    // Apollo config and endpoint for graph ql
    apollo: {
      includeNodeModules: true,
      clientConfigs: {
        default: '@/apollo/client-configs/default.js' // This is where you'll set up the client and import the possible fragment types
      }
    },
    

    现在我们在apollo/client-configs/default.js 中使用片段模式文件(我们将创建)创建 apollo 客户端

    import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
    import schema from './schema.json';
    const fragmentMatcher = new IntrospectionFragmentMatcher({
        introspectionQueryResultData: schema
      })
    
    export default ({req, app}) => {
        const token = process.env.GRAPHQL_TOKEN
        return {
            httpEndpoint: process.env.API_ENDPOINT,
            getAuth: () => `Bearer ${token}`, // remove if you're using the public schema
            cache: new InMemoryCache({ fragmentMatcher }),
        }
    }
    
    
    

    现在在apollo/client-configs/ 中保存一个空的schema.json 文件。

    接下来,我们需要设置脚本以在nuxtServerInit 上查询和生成此架构。您需要fs 来编写您的架构文件。您可以使用 NPM 安装它:npm install --save fs

    安装后,返回到您的 nuxt.config 并将 fs 添加到构建中:

    build: {
      extend (config, ctx) {
        config.node = {
          fs: 'empty'
        }
      }
    }
    

    然后在你的store/index.js:

    import Vuex from 'vuex';
    import fetch from 'node-fetch';
    import fs from 'fs';
    
    
    const createStore = () => {
      return new Vuex.Store({
        actions: {
            async nuxtServerInit({commit}, {app}) {
    
                // only update fragements locally
                if (process.env.NODE_ENV == 'local') {
                     
                    // LOAD FRAGMENT TYPES AND STORE IN FILE
                    // APOLLO READS THIS FILE LATER
                    fetch(process.env.API_ENDPOINT, {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json', authorization: 'Bearer ' + process.env.GRAPHQL_TOKEN, },
                        body: JSON.stringify({
                            variables: {},
                            query: `
                                {
                                    __schema {
                                        types {
                                            kind
                                            name
                                            possibleTypes {
                                                name
                                            }
                                        }
                                    }
                                }
                            `,
                        }),
                    })
                    .then(result => result.json())
                    .then(result => {
                        // here we're filtering out any type information unrelated to unions or interfaces
                        const filteredData = result.data.__schema.types.filter(
                        type => type.possibleTypes !== null,
                        );
                        result.data.__schema.types = filteredData;
                        fs.writeFile('./apollo/client-configs/schema.json', JSON.stringify(result.data), err => {
                            if (err) {
                                console.error('Error writing fragmentTypes file', err);
                            }
                        });
                    });
    
                }
                
            },
        }
      });
    };
    
    export default createStore
    
    

    您的架构现在应该在架构文件的本地生成,并且该文件将存储在 apollo 缓存中。

    【讨论】:

    • fs 如图所示移动了 here ,最重要的是,您 don't need to install fs 因为它与 Node 一起开箱即用(因此,与 Nuxt 一起使用)。此外,如果您仅使用 Nuxt 使用 SPA 模式(为什么,但仍然如此),这将不起作用,因为您将使用 yarn build 而不是 yarn generate 并且它将引入节点服务器未被调用的事实。 nuxtjs.org/docs/2.x/concepts/nuxt-lifecycle/#server 感谢您的指导。 :)
    【解决方案2】:

    任何人来这里是因为他们使用的是无头工艺 CMS,上面的答案是正确的,但为了节省您的阅读时间,基本上您必须让 Apollo 了解架构。

    import possibleTypes from './possibleTypes.json';
    import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
    const fragmentMatcher = new IntrospectionFragmentMatcher({
        introspectionQueryResultData: possibleTypes
    })
    

    在您定义客户的地方添加以下内容

    cache: new InMemoryCache({
        fragmentMatcher
    })
    

    要生成您的架构,您可以执行以下查询一次,然后将结果粘贴到 possibleTypes.json(不推荐,因为您会经常这样做)或者将该过程添加到您的 nuxtInitServer 函数中自动更新。

    query {
      __schema {
        types {
          name
          kind
          possibleTypes {
            name
            description
          }
        }
      }
    }
    

    【讨论】:

    • 嗨@mylesthe.dev 感谢您发布此消息-我正在尝试使用 Nuxt 转换为图形 QL,但我对两者都比较陌生。对于多个矩阵字段查询,我遇到了这个问题。您是否有机会提供更多关于我将上述每个 sn-ps 放置在 Nuxt 中的何处以全局解决此问题的背景信息?
    • @ToddPadwick 给你发了一些例子 :)
    【解决方案3】:

    如文档所述,只有在使用 apollo-client 3.0 版或更高版本(目前处于测试阶段)时才能使用 possibleTypes。除非您使用@apollo/client 包,如here 所示,否则传入possibleTypes 参数将无济于事。

    此外,您需要确保传入的对象中的每个属性都是联合或接口的名称,而不是字段的名称。来自docs

    您可以将 possibleTypes 选项传递给 InMemoryCache 构造函数,以指定架构中的超类型-子类型关系。此对象将接口或联合类型(超类型)的名称映射到实现或属于它的类型(子类型)。

    换句话说,您可以使用contentEngine 字段的类型名称,而不是使用contentEngine 作为键。

    如果您使用的是早期版本的apollo-client,则需要按照文档here 中的说明创建IntrospectionFragmentMatcher

    【讨论】:

    • 谢谢丹尼尔。你的回答让我找到了this thread,它帮助我弄清楚了如何使用 Nuxtjs 实现 Apollo 的 IntrospectionFragmentMatcher。
    猜你喜欢
    • 2022-07-29
    • 2020-01-03
    • 2020-09-11
    • 2022-12-14
    • 2023-03-19
    • 2023-03-21
    • 2019-04-30
    • 2017-10-23
    • 2020-01-17
    相关资源
    最近更新 更多