Graphql-code-generator: Duplicate TypeScript fragment imports with React Apollo

Created on 7 May 2020  ·  14Comments  ·  Source: dotansimha/graphql-code-generator

Describe the bug

It looks like it's the code generated by the typescript-operations plugin. I'm just using some fragments in some queries, like:

import gql from "graphql-tag"
import { entryFieldsFragment, folderFieldsFragment, projectFieldsFragment } from "graphql/fragments"

const someMutation = gql`
  mutation Bla(
    $projectUuid: UUID!
    $folderUuid: UUID!
  ) {

  ...

  ${entryFieldsFragment}
  ${folderFieldsFragment}
`

I've not duplicate the imports in this file, but the fragments are used multiple times within this file in different queries. Interestingly though, it's duplicating an import for a fragment I'm only using once in the file.

To Reproduce

Steps to reproduce the behavior:

https://codesandbox.io/s/nifty-night-j4mhx

This one took some reproducing, but it does give a lot of clues about what's going on. In the above CodeSandbox I've used the same config we have locally and created a dummy schema. I've also mimicked the relevant part of our folder structure.

What I've observed there is that the generated files' imports seem to be somehow linked if the input filename is the same (e.g. users.ts in 2 different folders, each with GraphQL queries in - the output seems linked for both of those files with the same name). If I import a fragment in one, but not the other it imports the fragment in both generated files. The issue seems to come in when the imports aren't identical in both files (not in the CodeSandbox I've just changed the order of those imports and that's confused it into generating duplicate imports).

In my local exmaple, I have 2 shared fragment imports in both separate source files (like the user.ts files in the CodeSandbox) and 1 different fragment. The generated result looks like both concatenated (without de-duplication). It's also worth noting, the particular imports that are duplicated in my local environment are in the same order in both files, there are just additional fragment imports. I think either scenario leads to this duplicate import result.

It looks like in 1.13.2 the generated import format changed and the bug was introduced with that, seems like the ___Doc imports were split out then.

  1. My GraphQL schema:

Closed source, sorry!

  1. My GraphQL operations:

Closed source, sorry!

  1. My codegen.yml config file:
overwrite: true
schema:
- "../management/schema.graphqls"
documents:
- "src/**/*.{ts,tsx}"
- "!src/**/*.generated.{ts,tsx}"
generates:
  src/types.ts:
    plugins:
    - typescript
    config:
      scalars:
        Date: string # TODO: Might not be the right type to use?
        UUID: string
  src/:
    preset: near-operation-file
    presetConfig:
      extension: .generated.ts
      baseTypesPath: types.ts
    plugins:
    - "typescript"
    - "typescript-operations"
    - "typescript-react-apollo"
    - "fragment-matcher"
    config:
      withComponent: false
      withHooks: true
      withHOC: false
      scalars:
        Date: string # TODO: Might not be the right type to use?
        UUID: string

Expected behavior

  • No duplicate imports in the generated code.
  • Generated source code using near-operation-file shouldn't be affected by non-nearby operations (i.e. if I import a fragment in one folder, it shouldn't show up in another folder's generated code).

Environment:

  • OS: MacOS 10.15.4
  • @graphql-codegen/...: v1.13.5
  • NodeJS: v12.16.3 (lts/erbium)
bug plugins waiting-for-release

Most helpful comment

Fixed in v1.15.2

All 14 comments

I'm having the same issue, but couldn't really reproduce it with a simpler schema.

I came across the same behavior in a different project with a much smaller schema so i managed to reproduce:
https://github.com/lkleuver/graphql-codegenerator-test

Hi there,

same here, but I think is not related to react apollo, I'm not using it.
This behavior comes up with version 1.15.0 and in the previous versions is not present

Here my config:
```yaml
overwrite: true
schema: "src/gql-schema-specs//.graphql"
documents: "src/gql-documents/
/.graphql"
hooks:
afterAllFileWrite:
- prettier --write
generates:
src/gql-generated/graphql.ts:
plugins:
- add: "// tslint:disable"
- "typescript"
- "typescript-operations"
- "fragment-matcher"
config:
typesPrefix: I
declarationKind: 'interface'
skipTypename: false
types/graphql.d.ts:
plugins:
- "typescript-graphql-files-modules"


and here and example of document causing the issue:
```graphql
fragment nsInfo on NamespaceInfo {
    ID
}

fragment nsList on NamespacesList {
  totalCount
  searchCount
  ns {
    ...nsInfo
  }
}

query searchNamespaces(
  $limit: Int!
  $offset: Int!
) {
  searchNamespaces(
    filters: {
      limit: $limit
      offset: $offset
    }
  ) {
    ...nsList
  }
}

Is there a work around available? I'm having the same problem.

In my case, it only seems to be the fragments generated by typescript-operations that end up being twice in the generated output.

Checked with:

cat generated/graphql.tsx | grep "export type" | sort | uniq -cd | sort -nr

Found the work around / fix, and submitted a PR. In the mean while,

In file node_modules/@graphql-codegen/typescript-operations/index.cjs.js

update line ~ 128

    const visitorResult = graphql.visit(allAst, {
        leave: visitor,
    });

-   let content = visitorResult.definitions.join('\n');
+   let content = Array.from(new Set(visitorResult.definitions)).join('\n');

    if (config.globalNamespace) {

Glad to see the core issue here being fixed, thank you very much for that! :)

I'm not sure if one other (smaller) thing was missed along the way with this one; it's not just duplicate imports (though, that's the only thing that's causing problems). It looked like the source of the duplicate imports was something to do with using multiple ts files with same name, with queries inside, importing the same fragement, i.e.

foo/
  graphql.ts - Imports fragment "BazFragment"
bar/
  graphql.ts - Imports fragment "BazFragment" and "QuxFragment"

In the above case, when using the near-operation-file preset, despite foo/graphql.ts _not_ importing QuxFragment, the generated output for both files (e.g. foo/graphql.generated.ts and bar/graphql.generated.ts respectively) would both contain all imports used in both files with the same name (prior to the fix, including the duplicates, i.e. both generated files would do something like import { BazFragment, BazFragment, QuxFragment } ...) despite the imports only being relevant to one of the generated files - they just happened to share the same file name.

I'll check if this is still the case, but it seems quite possible that there's something that builds up the imports by filename or something, and they all end up getting merged into one set of imports for all files with the same name?

I guess this might not really be considered a problem, but I think it's probably the original source of this bug in my original case.

EDIT: Just check this in 1.15.0, the generated file when using near-operation-file does still contain imports that aren't used in the operation file, but are used in a different operation file with the same name in a different folder. It shouldn't cause any issues, but I guess it might be useful to be aware of it.

You are right @seeruk , thank you!

though most duplicate imports are gone, I still have one file that shows the same behavior (1.15.1-alpha-12a4da72.33+12a4da72).

Really hard to pinpoint what causes this since it's a fairly large project/schema

@lkleuver I think it's related to the usage of graphql-import within your file. Do you use import for fragments?

I write 3 files per “model” query.graphql mutation.graphql and fragments.graphql

No special import statements, was actually super happy codegen handles the imports for me :)

Ok that's great, are you still getting a duplicate fragment? maybe it's something you can reproduce somehow? is there something special about this fragment? (maybe it's being used more often, in different ways?)

@dotansimha it looks like my original reprorepo still shows the 'bug'
https://github.com/lkleuver/graphql-codegenerator-test

I think the fixes of @cahilfoley works. Thank you!
@lkleuver I tested it with your repo and it seems to work correctly. (1.15.2-alpha-2e49bc0f.0).

We'll release it very soon :)

Fixed in v1.15.2

Was this page helpful?
0 / 5 - 0 ratings