apollo-tooling
apollo-tooling copied to clipboard
Codegen collaboration with Apollo Codegen and GraphQL Code Generator
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:
- Integrate graphql-code-generator into Apollo Codegen while keeping Apollo Codegen as a wrapper (we don’t care about credit :) )
- 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
- Output
- Apollo codegen yields multiple files - a file per input file, and GraphQL Codegen prefers a single file to be generated
- Multiple files are harder to maintain and are spread through the entire codebase, and generated output should always take into account the imports (which are not always predictable, especially in large/complex codebases, or monorepos).
- Performance - We’ve seen users ask for multiple files because they thought it would give them better build performance. In every single case, we’ve demonstrated to them that a single file with the right configurations is much faster
It’s still possible to generate multiple files (with a codegen
preset) if you wish to.
- Intermediate types
- GraphQL Codegen dropped default support for generating types of nested selection sets. We prefer to let developers have the ability to do that with GraphQL fragments. TypeScript (and Flow) allow you to access nested types easily and alias it if you wish to.
- GraphQL Codegen still supports generating intermediate types, but as a general approach, we recommend you not to do that (harder to maintain, causes mismatch issues, doesn’t scale with flexible configurations)
- Yaml config
- One of the goals of GraphQL Codegen is to be flexible as possible. That means, you can easily customize the output to match your needs, and especially makes it simpler to integrate with existing codebases.
- You can also use it programmatically, and have low-level over the input and output. You can also configure it with JSON or JavaScript if you don’t like YAML.
- Loaders
- Codegen automatically loads your schema from any source (file, local file, remote file, code files, GitHub, Apollo Graph Manager and more).
- GraphQL Codegen also knows how to extract and parse your GraphQL operations from your components code.
- You can easily customize the way you load your schema and your operations.
- Plugins
- Our community has over 100 plugins, for various languages, platforms and frameworks.
- Creating your own plugin is as simple as creating a local file in your repository. Codegen will pick it and integrate your custom plugin with other plugins.
- More than just basic types
- Resolvers signature - codegen allows you to generate type-safe resolvers signature (for TS, Flow and Java). You can also bring your own models types for types and context, and integrate it within the generated types. It will fully type your resolvers’ parent value, arguments, context and return value.
- Ready-to-use code - ensures better usage in large teams. You can generate fully-typed React-Apollo Hooks, Apollo-Angular Services for wrapping data fetching, Vue-Apollo data components and more.
- Fragment matcher - GraphQL Codegen can generate the fragments-matcher or
possibleTypesobject required by Apollo-Client. - Precompiled
DocumentNode- codegen can pre-compile GraphQL operations into DocumentNode and eliminate the need forgraphql-tag. - Introspection or schema-ast - Codegen has some abstractions for GraphQL and GraphQL-Tools, in order to make it simpler for your to create GraphQL introspection file, or even for merging schemas and printing it as GraphQL SDL.
- Activity on the repo
- We encourage the community to share all ideas, concepts and plugins they need. We aim to allow codegen to be flexible enough and simplify it’s integration in all codebases.
- We aim to release a new version with dependencies updates and bug fixes every week (and each change we do get it’s own alpha release automatically, so no need to wait for the new release in order to test new features or bug fixes). This has been that case for about 4 years and we don’t have any intention of stopping.
- Integration with other tools
- Federation - you can integrate your Apollo Federation backend and generate resolvers signatures based on the capabilities of each service.
- More integrations - TypeGraphQL, Apollo Local State, Gatsby (and more).
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
__typenameto identify the type correctly ;) - https://github.com/apollographql/apollo-tooling/issues/622 -
maybeValuein 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 (
useExactValueconfig) - 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
avoidOptionalsconfig. - 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:
graph/variant/key=> You can use apollo-graph loader for that.addTypename=>addTypenamecustomScalarsPrefix/passthroughCustomScalars=>scalarsoutputFlat=> Not supported, but could be added as a preset.globalTypesFile=> simply change the output name in codegen config.excludes=> negativeglobindocumentssectionendpoint/header/localSchemaFile=>schemaitem, with url loader.includes=>documentsmergeInFieldsFromFragmentSpreads=>flattenGeneratedTypesflag.namespace=> wrapper withaddplugintagName=>pluckConfigtarget=> list of plugins - this will support only flow / typescripttsFileExtension=> will update the output extension, but also we need to make sure to change some configurations related to enums (for exampleenumAsType: true) if the extension if.d.ts.useFlowExactObjects=> flow only,useFlowExactObjectsuseFlowReadOnlyTypes=> flow only,useFlowReadOnlyTypesuseReadOnlyTypes=>immutableTypesconfiguration flag
Thank you for this. I was interested in using hook generation and it looks like this is a good guide for me to migrate.
@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
...
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.
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.
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.
Does the graphql codegen type names match apollo's? e.g.
OperationOrFragmentName_fieldName_fieldName_fieldNameLocated in file:
flatPathOrFolderPath/OperationOrFragmentName.tsI 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-namingWe'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!
@dotansimha Does outputFlat option have some support?
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).
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
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
.envfile
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
@dotansimha Oh! totally missed that part, thank you!
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:
- 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"
}
- 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
}
...
- rewrite my queries used in
writeQueryfrom this
const WRITE_NETWORK_QUERY = gql`
query WriteNetwork {
networkStatus
}
`;
...
cache.writeQuery({
query: WRITE_NETWORK_QUERY,
data: {
networkStatus: {
__typename: 'Local__NetworkStatus',
online: true,
retrying: true,
},
},
});
to this
const WRITE_NETWORK_QUERY = gql`
query WriteNetwork {
networkStatus {
retrying
online
}
}
`;
....
- 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
- how to move local-schema.graphql and splited so each type can live in the folder where is defined his resolver
- how to generate
fragment-matcheused inpossibleTypesinInMemoryCache - how to get
typeDefsused bynew ApolloClient
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.
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!!
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!
Hi @antonvialibri1,
I am not certain that @graphql-codegen/typescript-compatibility is actually still required, could you try removing it and let me know?
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"
}
...
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.
Hi @antonvialibri1,
sorry for the delay.
Does GraphQL Codegen treat each
documentsentry 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!
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.
Hi @antonvialibri1,
do you still get the error if you disable/comment out the near-operation-file preset?
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.
@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
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!
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 @antonvialibri1,
The types are generated in colocated files because you configured the
near-operation-filepreset.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.
@antonvialibri1,
can you replace ./assets/shared/__generated__: by ./assets/shared/__generated__/types.ts:?
Hey all, what are the recommendations for configuring graphql-codegen to handle @client directives and cache-only fields?
Hey all, what are the recommendations for configuring
graphql-codegento handle@clientdirectives 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.
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
presetsfeature. We currently havenear-operation-filepreset that has output similar to the default ofapollo-tooling, but we don't have a preset that outputs something similar tooutputFlat(should be simple to create, btw).
Is there a guide for creating presets? How would I go about doing this?