apollographql / apollo-tooling

✏️ Apollo CLI for client tooling (Mostly replaced by Rover)
https://apollographql.com
MIT License
3.04k stars 469 forks source link

Codegen collaboration with Apollo Codegen and GraphQL Code Generator #2053

Open dotansimha opened 4 years ago

dotansimha commented 4 years ago

Hello Apollo team and Apollo Codegen users!

I’m Dotan and I’ve created a library called graphql-code-generator, which we maintain for the past 4 years that aims to solve some of the same issues as Apollo Codegen.

While working with a very large codebase of one of our new clients that was using Apollo Codegen, we’ve seen that the support for Apollo Codegen and it’s issues has slowed down in recent years, (looking at the history of the apollo-codegen-core, apollo-codegen-flow and the apollo-codegen-typescript libraries, it looks like the last meaningful workload was made around August 2018) and we wanted to offer our help!

On the following issue I will try to describe everything I can about the 2 codegens, in order to collaborate together on two possible paths:

  1. Integrate graphql-code-generator into Apollo Codegen while keeping Apollo Codegen as a wrapper (we don’t care about credit :) )
  2. An easy path for Apollo Codegen users to migrate to simply using graphql-code-generator

At the end, the goal here is to share all the work we’ve done in graphql-code-generator with Apollo and it’s community, in order to help Apollo in whatever way Apollo would see fit.

I will write about the difference between the codegens as they are today, two possible migration paths and a list of all open issues on Apollo Codegen that could be addressed by this collaboration.

We would love any feedback, from the great people at Apollo and it’s amazing community members!

We are currently just talking about the Typescript and Flow generators, as @designatednerd has been doing amazing work on the Swift codegen so no need for our help there! (But we are still happy to help and collaborate there if needed, as we have Swift codegen plugins maintained by our community).

Ok here we go:

We’ve reviewed the implementation of Apollo Codegen and reviewed all open issues related to codegen on this repo and came up with a possible plan to move forward we would love your feedback on.

There are some differences in the generated output of the two generators. We’ll explain here the differences in philosophies but we’ve also created a configuration for graphql-code-generator that generates similar output to Apollo Codegen and supports all the flag options of the Apollo CLI in order to make the switch easy and for you to have the option to gradually adopt our best practices or to simply stick with your own.

It is also a good time to kick start this collaborative initiative as we’ve started planning our next major version, GraphQL Code Generator 2.0, and would be great to get Apollo and the Apollo community be an active part in shaping that next release! (Including the new TypedDocumentNode plugin)

First, what is GraphQL Codegen and what are the Differences compared to Apollo Codegen

Here we try to describe the current differences between the tools, even though they can be almost identical with the right configuration in GraphQL Code Generator

Possible Migration Guide

As an Apollo Codegen user that wishes to migrate to GraphQL-Codegen, you have 2 options - either to use GraphQL Codegen and have a very similar output (with zero to minimal code changes), or adjust your project to the concepts of GraphQL Codegen. You should choose according to the size of your codebase and it’s complexity.

Option 1: Migrate to GraphQL-Codegen concepts

One of the major differences is the output itself - codegen aims to generate a single file with all the types. It’s easier for the IDE and for the TypeScript compiler.

The equivalent for TypeScript types based on GraphQL schema and operations, is the following configuration:

schema: PATH_OR_URL_TO_SCHEMA
documents: GLOB_EXPRESSION_FOR_OPERATIONS
generates:
  ./src/types.ts:
    plugins:
      - typescript
      - typescript-operations

You can start with it, and gradually extend it with more plugins and more features, according to your needs.

Option 2: Have the same output

This solution will leverage more complex codegen features and configurations, in order to create output that will be compatible with the same file-names and identifiers names that Apollo-Codegen creates today.

The following configuration file will help you:

# The value you are using today for `client:download-schema` - no need to download, store and then
# use it - codegen does that automatically.
schema:
  - PATH_OR_URL_TO_SCHEMA
documents:
  - GLOB_EXPRESSION_FOR_OPERATIONS # Equivalent for `--includes` flag, you can also use negative glob to `--excludes`
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates: 
  ./src/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates based types based on your schema
 ./src/: # Points to your project root directory.
    preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig: {
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations

This should create output that is very similar and compatible with the existing Apollo-Codegen implementation, and should make it simpler for you to migrate. Also, most of the configuration flags of Apollo-Codegen are supported in codegen, so if you are using custom setup, you should be able to use the base file above.

If your codebase is using intermediate types, you can add typescript-compatibility plugin to get those generated for you.

List of issues / PRs and their state compared to GraphQL-Codegen

Issues

* https://github.com/apollographql/apollo-tooling/issues/1414 - graphql-codegen have it by default, and it’s customizable (`namingConvention`) * https://github.com/apollographql/apollo-tooling/issues/1414#issuecomment-627727600 - Maybe we can create a plugin for intermediate types, just for annoying people like that. I think our recent blog post about codegen will help * https://github.com/apollographql/apollo-tooling/issues/979 - We have it built-in in our loaders, you can pass assumeValidSDL and it will skip validation. Maybe it should be better documented. * https://github.com/apollographql/apollo-tooling/issues/1568 - In our codegen it will generate it correctly, and you’ll be able to use `__typename` to identify the type correctly ;) * https://github.com/apollographql/apollo-tooling/issues/622 - `maybeValue` in config * https://github.com/apollographql/apollo-tooling/issues/1388 - Works in codegen, we can load fragment from packages (either code or exports) * https://github.com/apollographql/apollo-tooling/issues/1436 - Works in our codegen, throws error. * https://github.com/apollographql/apollo-tooling/issues/888 - Not supported yet. * https://github.com/apollographql/apollo-tooling/issues/1803 - Codegen will throw an error (valid behaviour) * https://github.com/apollographql/apollo-tooling/issues/1800 - Available in codegen (`useExactValue` config) * https://github.com/apollographql/apollo-tooling/issues/1767 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/988 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1043 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1044 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1735 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1204 - We prefer not to use namespaces in TS. But we do have an example for wrapping all types with an interface (using add plugin). * https://github.com/apollographql/apollo-tooling/issues/791 - In codegen it’s possible to add it manually to the codegen schema, so it will work. * https://github.com/apollographql/apollo-tooling/issues/1576 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1297 - Codegen status update is based on listr, and not verbose when not needed. * https://github.com/apollographql/apollo-tooling/issues/1366 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/604 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1161 - Not needed in codegen. * https://github.com/apollographql/apollo-tooling/issues/1310 - Not needed in codegen. * https://github.com/apollographql/apollo-tooling/issues/1207 - Not needed in codegen. * https://github.com/apollographql/apollo-tooling/issues/1036 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/873 - Available in codegen, because we load everything from scratch every execution. * https://github.com/apollographql/apollo-tooling/issues/1375 - Works in codegen. * https://github.com/apollographql/apollo-tooling/issues/1046 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/932 - Works in codegen. * https://github.com/apollographql/apollo-tooling/issues/833 - Codegen does that by default. * https://github.com/apollographql/apollo-tooling/issues/877 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1223 - You can distinguish types with __typename easily. * https://github.com/apollographql/apollo-tooling/issues/1760 - Codegen doesn’t change the sort, it will be used as-is, using graphql-js library. * https://github.com/apollographql/apollo-tooling/issues/1920 - Codegen doesn’t stop during watch mode, it just waits for changes and re-runs. * https://github.com/apollographql/apollo-tooling/issues/1850 - Codegen works with Yarn2 PnP. * https://github.com/apollographql/apollo-tooling/issues/2016 - Codegen allows you to customize the output and choose between interface or type. * https://github.com/apollographql/apollo-tooling/issues/2030 - Codegen doesn’t produce empty files. * https://github.com/apollographql/apollo-tooling/issues/2044 - Field policies can be represented as a GraphQL schema, and then loaded directly into Codegen just like any other schemas.

PRs

* https://github.com/apollographql/apollo-tooling/pull/1854 - Supported it codegen. * https://github.com/apollographql/apollo-tooling/pull/2043 - It shouldn’t change it in codegen. * https://github.com/apollographql/apollo-tooling/pull/1766 - Configurable with `avoidOptionals` config. * https://github.com/apollographql/apollo-tooling/pull/1750 - Available using `enumsAsTypes` * https://github.com/apollographql/apollo-tooling/pull/1504 - Codegen supports loading schema from local files, url and more.

Configuration mapping

The following is a reference for configuration mapping between Apollo-Codegen and GraphQL-Codegen, you might find it helpful it you are in the process of migrating it:

kaleb commented 4 years ago

Thank you for this. I was interested in using hook generation and it looks like this is a good guide for me to migrate.

kaleb commented 4 years ago

@dotansimha one thing left out is the apollo option of --passthroughCustomScalars. What I did was add the scalars key to my codegen.yml file:

config:
  scalars:
    DateTime: string
    Float: number
    ...
jimisaacs commented 3 years ago

What is this?

      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming

We've been using apollo for years now, and I've never seen this naming convention used in output.

jimisaacs commented 3 years ago

Does the graphql codegen type names match apollo's? e.g.

OperationOrFragmentName_fieldName_fieldName_fieldName

Located in file: flatPathOrFolderPath/OperationOrFragmentName.ts

I ask, because a significant deviation from this would hurt quite a bit.

jimisaacs commented 3 years ago

I've assessed transitioning, and TBH, I find Apollo's generated types/interfaces much simpler to reason about. Though I won't lie that I'm coming with a bias, based on years of use, and thousands of usages in our codebase.

dotansimha commented 3 years ago

Does the graphql codegen type names match apollo's? e.g.

OperationOrFragmentName_fieldName_fieldName_fieldName

Located in file: flatPathOrFolderPath/OperationOrFragmentName.ts

I ask, because a significant deviation from this would hurt quite a bit.

GraphQL Codegen doesn't generate intermediate types by default. There are solution, but in most cases just using fragments makes it simpler (and more correct in terms of GraphQL workflow).

What is this?

      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming

We've been using apollo for years now, and I've never seen this naming convention used in output.

You are right, maybe it was outdated :) But the point is that you can customize it.

I've assessed transitioning, and TBH, I find Apollo's generated types/interfaces much simpler to reason about. Though I won't lie that I'm coming with a bias, based on years of use, and thousands of usages in our codebase.

Sure. I don't think there is a right/wrong choice here. It all depends on your workflow and what works best for you!

xxleyi commented 3 years ago

@dotansimha Does outputFlat option have some support?

dotansimha commented 3 years ago

outputFlat

With codegen, we recommend generated all types into a single file. When you want to generate more than one file (or, separate files based on operations/types), you can use presets feature. We currently have near-operation-file preset that has output similar to the default of apollo-tooling, but we don't have a preset that outputs something similar to outputFlat (should be simple to create, btw).

dylanwulf commented 3 years ago

strongly considering switching over to GraphQL Code Generator, mainly due to #2232 and #1750 (that last one has been open for 1.5 years now with no word from maintainers!). The one thing GraphQL Code Generator can't do is take my schema URL from my .env file

dotansimha commented 3 years ago

strongly considering switching over to GraphQL Code Generator, mainly due to #2232 and #1750 (that last one has been open for 1.5 years now with no word from maintainers!). The one thing GraphQL Code Generator can't do is take my schema URL from my .env file

see https://www.graphql-code-generator.com/docs/getting-started/codegen-config#environment-variables and https://www.graphql-code-generator.com/docs/getting-started/require-field#dotenv-integration

dylanwulf commented 3 years ago

@dotansimha Oh! totally missed that part, thank you!

nathanredblur commented 3 years ago

sorry, is not clear for me, how to generate fragment-matcher and typeDef configurations used in apollo client.

this is my long road (and difficulties) to generate this types:

  1. add a fixed version in my package json for my mono-repo (that I should remove because in the mono repo there are modules that require older versions)
    "resolutions": {
    "graphql": "^15.5.3"
    }
  2. move all my schemas used in my local resolvers out of his file from this
    
    // AuthUser.js
    export const schema = gql`
    extend type Auth__User {
    canUseSomething: Boolean
    }
    `;

export const resolvers = { ...

to a file that needs to be in the root folder (because in other location generate issues.) with all local schemas of all my resolvers

// local-schema.graphql extend type Auth__User { canUseSomething: Boolean } ...


3.  rewrite my queries used in `writeQuery`
from this

const WRITE_NETWORK_QUERY = gql query WriteNetwork { networkStatus } ; ... cache.writeQuery({ query: WRITE_NETWORK_QUERY, data: { networkStatus: { typename: 'LocalNetworkStatus', online: true, retrying: true, }, }, });

to this

const WRITE_NETWORK_QUERY = gql query WriteNetwork { networkStatus { retrying online } } ; ....

4.  run this long commands

"apollo:download": "apollo service:download --endpoint=https://app.stg.airtm.io/graphql src/lib/apollo/graphql.schema.json",

"apollo:generate": "apollo codegen:generate --localSchemaFile=src/lib/apollo/graphql.schema.json,local-schema.graphql --target=typescript --tagName=gql",


and I don't know
1.  how to move  local-schema.graphql and splited so each type can live in the folder where is defined his resolver
2. how to generate `fragment-matche`  used in `possibleTypes` in `InMemoryCache`
3. how to get `typeDefs` used by ` new ApolloClient`
franleplant commented 2 years ago

One other thing not mentioned here is that apollo codegen can get really slow and I know that graphql-codegen scales really well.

Would be awesome to automate the migration, for larger codebases.

poppywu commented 2 years ago

Hi, thank you for this migration file, it's super helpful! For the customScalarsPrefix / passthroughCustomScalars => scalars, currently I have --customScalarsPrefix=test$, how should I config scalars to obtain the same prefix? Are there any example? Thanks!!

antonvialibri1 commented 2 years ago

I tried migrating from Apollo Codegen to GraphQL Codegen, but it didn't work.

We generate GraphQL types through Apollo Codegen using the following command and apollo.config.js file:

apollo client:codegen --target typescript --outputFlat
module.exports = {
  client: {
    service: {
      name: 'project',
      localSchemaFile: 'storage/app/lighthouse-schema.graphql'
    },
    includes: [
      'assets/shared/**/*.js',
      'assets/project1/src/**/*.js',
      'assets/project2/js/**/*.js',
      'assets/project3/src/**/*.js'
    ]
  }
};

It's a monorepo project which uses Yarn workspaces. The GraphQL schema is generated by Lighthouse (lighthouse-schema.graphql).

apollo client:codegen --target typescript --outputFlat scans all the JS source code in all projects (mainly React components that use @apollo/client's gql, useQuery and useMutation) and generates multiple .ts type files within the __generated__ folder.

This is our baseline and it works well. We decided to give GraphQL Codegen a try as apollo CLI codegen seems to be deprecated and still depends on the graphql package at version 15 (the current major version as of today is 16).

Therefore, I've installed GraphQL Codegen and upgraded the graphql package to major version 16:

// package.json
...
"dependencies": {
    "graphql": "^16.5.0",
    ...
},
"devDependencies": {
    "@graphql-codegen/typescript": "2.7.2",
    "@graphql-codegen/typescript-compatibility": "2.1.5",
    "@graphql-codegen/typescript-operations": "2.5.2",
    "@graphql-codegen/typescript-react-apollo": "3.3.2",
    "@graphql-codegen/typescript-document-nodes": "2.3.2",
    "@graphql-codegen/fragment-matcher": "3.3.0",
    "@graphql-codegen/typescript-graphql-files-modules": "2.2.0",
    "@graphql-codegen/introspection": "2.2.0",
    "@graphql-codegen/cli": "2.9.1",
    "@graphql-codegen/near-operation-file-preset": "2.4.0"
}
...

Then I've created the following config graphql-codegen.yml file by following @dotansimha's migration advice in this issue (https://github.com/apollographql/apollo-tooling/issues/2053#issue-666281081):

schema: "./storage/app/lighthouse-schema.graphql"
documents:
  - assets/shared/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project2/src/**/*.js
  - assets/project3/src/**/*.js
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates:
  ./assets/shared/__generated__/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates based types based on your schema
      - typescript-compatibility
  ./assets/shared/__generated__:
    preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations
      - typescript-compatibility

Now, when I run yarn graphql-codegen I get the following errors:

% yarn graphql-codegen        
yarn run v1.22.19
$ graphql-codegen --config graphql-codegen.yml
✔ Parse Configuration
⚠ Generate outputs
  ❯ Generate ./assets/shared/__generated__/globalTypes.ts
    ✔ Load GraphQL schemas
    ✔ Load GraphQL documents
    ✖ GraphQL Document Validation failed with 2 errors;
      Error 0: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/repositories/project/assets/project2/src/App.js:4:10
      Error 1: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/repositories/project/assets/project3/src/App.js:4:10
  ❯ Generate to ./assets/shared/__generated__ (using EXPERIMENTAL preset "near-operation-file")
    ✔ Load GraphQL schemas
    ✔ Load GraphQL documents
    ✖ visitFn.call is not a function
✨  Done in 3.29s.

UserContextFragment is a fragment defined in our JS code through @apollo/client's gql (it's defined in a JS file in the shared project which is shared between project1, project2 and project3). My question would be: why does GraphQL Codegen complain about this fragment if it's defined in a JS file within the assets/shared/src project which comes before the other projects in the documents section of graphql-codegen.yml? Does GraphQL Codegen disallow generating types this way?

visitFn.call is not a function is another error you can see from my output: I think (but I'm not sure) this one is related to @graphql-codegen/typescript-compatibility, as it seems that this plugin depends on graphql@15 (instead of 16).

What would be the correct way to migrate from Apollo Codegen in to GraphQL Codegen in this particular case?

Thank you!

charlypoly commented 2 years ago

Hi @antonvialibri1,

I am not certain that @graphql-codegen/typescript-compatibility is actually still required, could you try removing it and let me know?

antonvialibri1 commented 2 years ago

Hi @charlypoly,

Thank you for your reply. I tried removing @graphql-codegen/typescript-compatibility, but I still get an error when running yarn graphql-codegen:

% yarn graphql-codegen   
yarn run v1.22.19
$ graphql-codegen --config graphql-codegen.yml
Cannot find module 'typescript'
Require stack:
- /Users/me/repositories/project/node_modules/ts-node/dist/util.js
- /Users/me/repositories/project/node_modules/ts-node/dist/index.js
- /Users/me/repositories/project/cosmiconfig-typescript-loader/dist/cjs/loader.js
- /Users/me/repositories/project//node_modules/cosmiconfig-typescript-loader/dist/cjs/index.js
- /Users/me/repositories/project/node_modules/graphql-config/index.js
- /Users/me/repositories/project/node_modules/@graphql-codegen/cli/cjs/graphql-config.js
- /Users/me/repositories/project/node_modules/@graphql-codegen/cli/cjs/config.js
- /Users/me/repositories/project/node_modules/@graphql-codegen/cli/cjs/codegen.js
- /Users/me/repositories/project/node_modules/@graphql-codegen/cli/cjs/generate-and-save.js
- /Users/me/repositories/project/node_modules/@graphql-codegen/cli/cjs/cli.js
- /Users/me/repositories/project/node_modules/@graphql-codegen/cli/cjs/bin.js
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Here is the graphql-codegen.yml file:

schema: "./storage/app/lighthouse-schema.graphql"
documents:
  - assets/shared/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project2/src/**/*.js
  - assets/project3/src/**/*.js
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates:
  ./assets/shared/__generated__/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates based types based on your schema
      #- typescript-compatibility # <------------------------------------- Removed `typescript-compatibility`
  ./assets/shared/__generated__:
    preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations
      #- typescript-compatibility # <------------------------------------- Removed `typescript-compatibility`

Should I also try removing typescript? Thank you.

P.S.: I left the package.json as-is:

// package.json
...
"dependencies": {
    "graphql": "^16.5.0",
    ...
},
"devDependencies": {
    "@graphql-codegen/typescript": "2.7.2",
    "@graphql-codegen/typescript-compatibility": "2.1.5",
    "@graphql-codegen/typescript-operations": "2.5.2",
    "@graphql-codegen/typescript-react-apollo": "3.3.2",
    "@graphql-codegen/typescript-document-nodes": "2.3.2",
    "@graphql-codegen/fragment-matcher": "3.3.0",
    "@graphql-codegen/typescript-graphql-files-modules": "2.2.0",
    "@graphql-codegen/introspection": "2.2.0",
    "@graphql-codegen/cli": "2.9.1",
    "@graphql-codegen/near-operation-file-preset": "2.4.0"
}
...
antonvialibri1 commented 2 years ago

Tried removing typescript from the graphql-codegen.yml, still the same error.

Then I installed typescript as a dev dependency:

// package.json
...
"dependencies": {
    "graphql": "^16.5.0",
    ...
},
"devDependencies": {
    "@graphql-codegen/typescript": "2.7.2",
    "@graphql-codegen/typescript-compatibility": "2.1.5",
    "@graphql-codegen/typescript-operations": "2.5.2",
    "@graphql-codegen/typescript-react-apollo": "3.3.2",
    "@graphql-codegen/typescript-document-nodes": "2.3.2",
    "@graphql-codegen/fragment-matcher": "3.3.0",
    "@graphql-codegen/typescript-graphql-files-modules": "2.2.0",
    "@graphql-codegen/introspection": "2.2.0",
    "@graphql-codegen/cli": "2.9.1",
    "@graphql-codegen/near-operation-file-preset": "2.4.0",
    "typescript": "^4.7.4"
}
...

Re-ran yarn graphql-codegen and I still get the GraphQLDocumentError: Unknown fragment "UserContextFragment". error above.

I was wondering if GraphQL Codegen is able to understand that with this setup for documents:

documents:
  - assets/shared/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project2/src/**/*.js
  - assets/project3/src/**/*.js

I have a UserContextFragment defined within assets/shared/src/**/*.js shared project, then I refer to this fragment within project1, project2 and project3.

Apollo Codegen used to undestand that and would generate types for all queries/operations within project1, project2 and project3 that refer to UserContextFragment from shared.

Does GraphQL Codegen treat each documents entry separately and not as a whole? It seems to do it.

Thank you.

charlypoly commented 2 years ago

Hi @antonvialibri1,

sorry for the delay.

Does GraphQL Codegen treat each documents entry separately and not as a whole? It seems to do it.

GraphQL Code Generator does take documents as a whole before processing them.

I did an example project that tries to mimic your project structure and codegen configuration, and codegen is executing as expected: https://github.com/charlypoly/codegen-repros/tree/master/near-op-file-with-fragments

I would need much more information to help you migrate your project (ex: look at the content of this UserContextFragment definition). Could you reach out to me using our chat/mail system via https://the-guild.dev/ 👀 ?

We'll be able there to interact more easily and faster, thank you!

antonvialibri1 commented 2 years ago

UserContextFragment is defined in a file within assets/shared/src, so I guess it's included before all the other documents in the graphql-codegen.yml config file:

documents:
  - assets/shared/src/**/*.js # <---- This project contains UserContextFragment 
  - assets/project1/src/**/*.js
  - assets/project2/src/**/*.js
  - assets/project3/src/**/*.js

These are the contents of the assets/shared/contexts/UserContext.js file where that UserContextFragment is defined:

// assets/shared/contexts/UserContext.js

export const UserContextFragment = gql`
  fragment UserContextFragment on User {
    id
    user {
      firstname
      lastname
      email
    }
  }
`;

Then I have project1 and project3 which include that assets/shared/contexts/UserContext.js file, like this:

// assets/project1/src/App.js

import { UserContextFragment } from '@project/shared';

export const GET_USER_DATA = gql`
  query GetUserData {
    me {
      ...UserContextFragment
    }
  }
  ${UserContextFragment}
`;

...
// assets/project3/src/App.js

import { UserContextFragment } from '@project/shared';

export const GET_USER_DATA = gql`
  query GetUserData {
    me {
      ...UserContextFragment
    }
  }
  ${UserContextFragment}
`;

...

This file makes yarn graphql-codegen fail with the following error:

% yarn graphql-codegen                  
yarn run v1.22.19
$ graphql-codegen --config graphql-codegen.yml
✔ Parse Configuration
⚠ Generate outputs
  ❯ Generate ./assets/shared/__generated__/globalTypes.ts
    ✔ Load GraphQL schemas
    ✔ Load GraphQL documents
    ✖ GraphQL Document Validation failed with 2 errors;
      Error 0: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/project/assets/project1/src/App.js:4:10
      Error 1: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/project/assets/project3/src/App.js:4:10
  ✔ Generate to ./assets/shared/__generated__ (using EXPERIMENTAL preset "near-operation-file")
✨  Done in 3.87s.
charlypoly commented 2 years ago

Hi @antonvialibri1,

do you still get the error if you disable/comment out the near-operation-file preset?

antonvialibri1 commented 2 years ago

Hi @charlypoly,

tried removing near-operation-file:

schema: "./storage/app/lighthouse-schema.graphql"
documents:
  - assets/shared/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project1/src/**/*.js
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates:
  ./assets/shared/__generated__/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates based types based on your schema
#      - typescript-compatibility # <------------------------------------- Removed `typescript-compatibility`
  ./assets/shared/__generated__:
    #preset: near-operation-file # Tells codegen to generate multiple files instead of one # <------------ Commented out
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations
#      - typescript-compatibility # <------------------------------------- Removed `typescript-compatibility`

I still get the error though:

% yarn graphql-codegen
yarn run v1.22.19
$ graphql-codegen --config graphql-codegen.yml
✔ Parse Configuration
⚠ Generate outputs
  ❯ Generate ./assets/shared/__generated__/globalTypes.ts
    ✔ Load GraphQL schemas
    ✔ Load GraphQL documents
    ✖ GraphQL Document Validation failed with 2 errors;
      Error 0: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/project/assets/project1/src/App.js:4:10
      Error 1: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/project/assets/project3/src/App.js:4:10
  ❯ Generate ./assets/shared/__generated__
    ✔ Load GraphQL schemas
    ✔ Load GraphQL documents
    ✖ GraphQL Document Validation failed with 2 errors;
      Error 0: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/project/assets/project1/src/App.js:4:10
      Error 1: GraphQLDocumentError: Unknown fragment "UserContextFragment".
      at /Users/me/project/assets/project3/src/App.js:4:10
✨  Done in 5.02s.
charlypoly commented 2 years ago

@antonvialibri1 I just spotted a possible typo.

You shared your documents being the following:

documents:
  - assets/shared/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project1/src/**/*.js

The path to the shared project is assets/shared/src/**/*.js, however, you indicated that your UserContextFragment fragment is defined assets/shared/contexts/UserContext.js (which is not match by assets/shared/src/**/*.js) :

// assets/shared/contexts/UserContext.js

export const UserContextFragment = gql`
  fragment UserContextFragment on User {
    id
    user {
      firstname
      lastname
      email
    }
  }
`;

Is assets/shared/contexts/UserContext.js the correct path? If so, the documents value should be changed to:

documents:
  - assets/shared/**/*.js
  - assets/project1/src/**/*.js
  - assets/project1/src/**/*.js
  - assets/project1/src/**/*.js
antonvialibri1 commented 2 years ago

Hi @charlypoly,

oh, yeah, what a shame! 😅 I set those paths wrong in the GraphQL Codegen's config file.

I tried again and this config generates the types now 🎉 :

schema: "./storage/app/lighthouse-schema.graphql"
documents:
  - assets/shared/**/*.js
  - assets/project1/src/**/*.js
  - assets/project2/src/**/*.js
  - assets/project3/src/**/*.js
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates:
  ./assets/shared/__generated__/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates based types based on your schema
#      - typescript-compatibility # <------------------------------------- Removed `typescript-compatibility`
  ./assets/shared/__generated__:
    preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations
#      - typescript-compatibility # <------------------------------------- Removed `typescript-compatibility`

The only thing that I noticed now is that the *.graphql.interface.ts files are generated inline with the related file (e.g. App.js component and App.graphql.interface.ts) instead of being generated all within the ./assets/shared/__generated__ folder.

Shouldn't the following configuration generate all files within ./assets/shared/__generated__:? If not, how can I generate all *.graphql.interface.ts files within that folder instead of having them inline with their related file?

  ./assets/shared/__generated__:
    preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations

Thank you!

charlypoly commented 2 years ago

Hi @antonvialibri1,

The types are generated in colocated files because you configured the near-operation-file preset.

Try removing the following lines:

preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
antonvialibri1 commented 2 years ago

Hi @antonvialibri1,

The types are generated in colocated files because you configured the near-operation-file preset.

Try removing the following lines:

preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig:
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file

Hi @charlypoly,

I tried removing those lines:

schema: "./storage/app/lighthouse-schema.graphql"
documents:
  - assets/shared/**/*.js
  - assets/project1/src/**/*.js
  - assets/project2/src/**/*.js
  - assets/project3/src/**/*.js
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates:
  ./assets/shared/__generated__/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates base types based on your schema
  ./assets/shared/__generated__:
#    preset: near-operation-file # Tells codegen to generate multiple files instead of one
#      presetConfig:
#        extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
#        baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations

However, the outcome is just an empty assets/shared/__generated__/globalTypes.ts file being generated, without any types.

charlypoly commented 2 years ago

@antonvialibri1,

can you replace ./assets/shared/__generated__: by ./assets/shared/__generated__/types.ts:?

jviall commented 2 years ago

Hey all, what are the recommendations for configuring graphql-codegen to handle @client directives and cache-only fields?

charlypoly commented 2 years ago

Hey all, what are the recommendations for configuring graphql-codegen to handle @client directives and cache-only fields?

Hi @jviall,

We have a dedicated documentation page on this matter: https://www.the-guild.dev/graphql/codegen/docs/integrations/apollo-local-state

Let me know if you have any question, you can reach us through our Support chat available through the website.

AK3030 commented 1 year ago

outputFlat

With codegen, we recommend generated all types into a single file. When you want to generate more than one file (or, separate files based on operations/types), you can use presets feature. We currently have near-operation-file preset that has output similar to the default of apollo-tooling, but we don't have a preset that outputs something similar to outputFlat (should be simple to create, btw).

Is there a guide for creating presets? How would I go about doing this?