You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用GraphQL Codegen生成的Typed DocumentNode片段创建查询

问题背景

我正在使用GraphQL Code Generator生成带类型的DocumentNode片段,示例代码如下:

export const MMovieConnectionFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MMovieConnection"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MMovieConnection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"mMovieActors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode<MMovieConnectionFragment, unknown>;

尝试使用上述片段创建简单的GraphQL查询,示例代码如下:

gql`query myQuery {
      myQuery {
          ...MMovieConnection
      }
  }
  ${MMovieConnectionFragmentDoc}
`

运行时抛出错误:Cannot read properties of undefined (reading 'source')

如果采用如下标准方式定义片段,查询可成功创建:

fieldsFragment = gql`fragment MMovieConnection on MMovieConnection {
    edges {
        node {
            id
        }
    }
}`;

对比两种片段对象发现:标准方式创建的片段与MMovieConnectionFragmentDoc结构基本等价,但前者额外包含loc属性,该属性下挂载了source属性,结构示例如下:

loc: {
    start: 0,
    end: 239,
    source: {
      body: "fragment MMovieConnection on MMovieConnection {\n            edges {\n                node {\n                    id\n                    mMovieActors {\n                        id\n                    }\n                }\n            }\n        }",
      name: "GraphQL request",
      locationOffset: {
        line: 1,
        column: 1,
      },
    },
  },

由此推断gql模板标签在查询中引入片段时,需要依赖对象上的loc与source属性,需要找到可直接使用MMovieConnectionFragmentDoc创建GraphQL查询的可行方法。

解决方案

报错核心原因是:graphql-tag提供的gql模板标签在处理插值传入的DocumentNode时,会默认读取节点上的loc.source字段做片段依赖解析、重复定义过滤,而GraphQL Code Generator默认生成的无字符串AST片段不携带loc字段,直接插值就会触发读取undefined属性的错误。
可行的解决方法有两种,按需选择即可:

  • 调整Code Generator配置,生成带loc属性的兼容片段
    如果你使用的是官方@graphql-codegen/client-preset,在codegen配置文件中修改documentMode配置项为graphqlTag,生成的片段会自动用gql标签包裹,自带完整的loc与source属性,可直接在gql模板中插值使用,不需要改动现有业务代码。配置示例:
    // codegen.ts 配置示例
    import type { CodegenConfig } from '@graphql-codegen/cli';
    
    const config: CodegenConfig = {
      schema: 'your-schema-path',
      documents: ['src/**/*.tsx'],
      generates: {
        'src/gql/': {
          preset: 'client',
          plugins: [],
          presetConfig: {
            documentMode: 'graphqlTag', // 新增该配置项
          }
        }
      }
    };
    export default config;
    
  • 不修改Codegen配置,通过AST合并方式组装查询
    如果不想改动codegen生成规则,可以跳过gql模板的插值逻辑,直接用AST合并工具把基础查询和生成的片段合并为完整的DocumentNode,这种方式不依赖loc属性,可直接使用生成的纯AST片段。
    首先安装依赖:
    npm install @graphql-tools/merge
    
    代码实现示例:
    import { gql } from 'graphql-tag';
    import { mergeTypeDefs } from '@graphql-tools/merge';
    import { MMovieConnectionFragmentDoc } from './gql/fragments';
    
    // 先定义不带片段插值的基础查询
    const baseQuery = gql`query myQuery {
      myQuery {
        ...MMovieConnection
      }
    }`;
    
    // 直接合并AST节点,得到完整可执行的查询
    const fullQuery = mergeTypeDefs([baseQuery, MMovieConnectionFragmentDoc]);
    

不推荐手动给生成的FragmentDoc补mock的loc属性,这种方式兼容性差,升级graphql-tag或codegen版本时容易出现隐性问题。

内容的提问来源于stack exchange,提问作者Matthew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 14:06:29