Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeated fragment spreading causes perf issues with near-operation-files + typescript-operations #752

Open
vhfmag opened this issue Jun 20, 2024 · 0 comments

Comments

@vhfmag
Copy link

vhfmag commented Jun 20, 2024

Which packages are impacted by your issue?

@graphql-codegen/near-operation-file-preset

Describe the bug

While investigating an issue with graphql codegen taking too long in the pipeline of one of my company's projects, I came across a performance issue caused when spreading a deeply nested fragment multiple times in the same file. The issue happens when near-operation-file and typescript-operations are used together, and is ultimately caused due to the first supplying repeated input to the latter.

Here's how it works:

  1. near-operation-file resolves document imports here and then generates a list of externalFragments for each given file here. That list includes all nested fragments, and if a fragment is spread N times in the same file, it and of its nested fragments will be included N times. externalFragments is then passed as a config to plugins here.
  2. typescript-operations includes externalFragments into allFragments here and then passes it to TypeScriptDocumentsVisitor here, which passes it to SelectionSetToObject here, which passes it to getFieldNames here.
  3. getFieldNames iterates over its first argument (selections) and when it finds a fragment spread, it calls itself passing loadedFragments.filter(def => def.name === selection.name.value).flatMap(...) as the selections argument here. That's where the issue happens: because the same fragment is included multiple times in loadedFragments, the recursive function call will iterate multiple times over the same fragment. If that fragment has a nested one, the same will happen to it, and so on.
  4. All that means that if a fragment is spread M times and has N levels of fragment spreads (e.g. if fragment A spreads fragment B, which spreads fragment C, which doesn't spread anything, N = 3), getFieldNames will be called at least M^N times.

Your Example Website or App

https://github.com/vhfmag/codegen-perf-issue-repro

Steps to Reproduce the Bug or Issue

  1. Clone the repo
  2. Run yarn codegen
  3. Add a new fragment to frags.ts and spread it into the last one
  4. Run yarn codegen — it should take 4 times as long as it did before because we spread fragment A 4 times in the ops.ts file
  5. Steps 3 & 4 can be repeated indefinitely

Example change:

BeforeAfter
// ...
const J = gql`
  fragment J on User {
    j
    ...K
  }
`;
const K = gql`
  fragment K on User {
    k
  }
`;
// ...
const J = gql`
  fragment J on User {
    j
    ...K
  }
`;
const K = gql`
  fragment K on User {
    k
    ...L
  }
`;
const L = gql`
  fragment L on User {
    l
  }
`;

Expected behavior

Time complexity should increase linearly with M & N

Screenshots or Videos

No response

Platform

  • OS: macOS & linux
  • NodeJS: 18.18.2
  • graphql version: 16.2.0
  • @graphql-codegen/near-operation-file-preset version(s): 3.0.0

Codegen Config File

{
  schema: "schema.graphql",
  documents: "src/**/*.ts",
  generates: {
    "types.ts": {
      preset: "near-operation-file",
      presetConfig: {
        baseTypesPath: "types.ts",
        folder: "__generated__",
      },
      config: {
        avoidOptionals: {
          field: true,
          inputValue: false,
          object: false,
          defaultValue: false,
        },
        arrayInputCoercion: false,
        extractAllFieldsToTypes: true,
        printFieldsOnNewLines: true,
        omitOperationSuffix: true,
        namingConvention: "keep",
      },
      plugins: ["typescript", "typescript-operations"],
    },
  },
}

Additional context

No response

@vhfmag vhfmag changed the title Repeat fragment spreading causes perf issues with near-operation-files + typescript-operations Repeated fragment spreading causes perf issues with near-operation-files + typescript-operations Jun 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant