graphql-code-generator
graphql-code-generator copied to clipboard
GraphQL Code Generator v5 Roadmap
This page is synced automatically from The Guild's Notion Notion page URL: https://www.notion.so/GraphQL-Code-Generator-v4-Roadmap-91923bfb2dee48eaa0d6a77666429968
At The Guild, we’ve decided to work as much as possible in public; that’s why we are opening the roadmaps for all of our projects.
The goals for this are:
- So you will know what we are working on, what we see as a higher priority, and know what to expect from our projects in the future
- So you can share your opinions and thoughts about what we do and influence our decisions
- So you can join us and contribute to our efforts!
Before laying down the roadmap of GraphQL Code Generator v3, we would like to thank all of you for being so many who use codegen daily and for contributing to making it such a complete project! 🚀
While some people judge that GraphQL is difficult, GraphQL Code Generator v3 aims to change that perspective by providing a unified configuration along with a smaller and simpler generated code.
By providing a unified package and configuration for all client-side use cases, all existing and future plugin alternatives will be moved to community repos.
Let’s now cover these changes in detail.
A unified configuration and package for all GraphQL clients
Most of the existing client-side plugins (typescript-react-apollo
, typescript-react-query
, etc) rely on the generation of hooks or SDKs that wrap the underlying GraphQL Client in a type-safe way.
However, the generation of hooks or SDK code brings many downsides:
- an unnecessary increase of the final bundle size
- misalignment between the generated hooks signature and the underlying GraphQL Client
- inconsistencies of configuration options and preset compatibility across packages (ex:
near-operation-file
compatibility)
To make GraphQL code generation great and simple, the v3 version will introduce two major changes:
- a new unique preset for all GraphQL clients, which include better developer experience, smaller bundle size, stronger typings, and easier-to-follow best practices
- a TypeScript-first configuration file that will allow configuration autocompletion
Here is how you can already configure codegen for all GraphQL Clients:
import { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.tsx'],
generates: {
'./src/gql/': {
preset: 'client',
plugins: []
}
}
}
export default config
The client
preset comes with a simple opinionated configuration and a lightweight types-only generation.
To try the new client
preset, please install the following dependencies:
yarn add graphql
yarn add -D typescript
yarn add -D @graphql-codegen/cli
yarn add -D @graphql-codegen/client-preset
First, start GraphQL Code Generator in watch mode:
yarn graphql-codegen --watch
Using GraphQL Code Generator will type your GraphQL Query and Mutations as you write them ⚡️
Now, each query or mutation written with the generated graphql()
function will be automatically typed!
For example, with Apollo Client (React):
import React from 'react';
import { useQuery } from '@apollo/client';
import { graphql } from './gql/gql';
import Film from './Film';
// here, `allFilmsWithVariablesQueryDocument` is fully typed!
const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
query allFilmsWithVariablesQuery($first: Int!) {
allFilms(first: $first) {
edges {
node {
...FilmItem
}
}
}
}
`);
function App() {
// Most GraphQL Clients know how to deal with typed GraphQL documents,
// providing typed data and typed variables
const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } });
return (
<div className="App">
{data && <ul>{data.allFilms?.edges?.map((e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />)}</ul>}
</div>
);
}
export default App;
Thanks to work made to integrate TypeDocumentNode
(the underlying plugin used by preset: client
) with most of the popular GraphQL clients, you no longer need hooks or SDK, simple GraphQL documents works!
We believe that the preset: client
approach is the way to get the best of TypeScript and GraphQL by:
- reducing the size of the generated bundle
- only the
graphql()
function needs to be imported (no type, hooks, document imports) - removing layers between your application and your chosen GraphQL Client
- providing stronger typings that will stay aligned with your chosen GraphQL Client
- offering you the best component isolation design by leveraging Fragment Masking
Finally, this new preset: client
has been properly tested on all popular GraphQL clients across most frameworks:
-
React
-
@apollo/client
(since3.2.0
, not when using React Components (<Query>
)) -
@urql/core
(since1.15.0
) -
@urql/preact
(since1.4.0
) -
urql
(since1.11.0
) -
graphql-request
(since5.0.0
) -
react-query
(with[email protected]
) -
swr
(with[email protected]
) -
@urql/exchange-graphcache
(since3.1.11
)
-
-
Svelte
-
@urql/svelte
(since1.1.3
)
-
-
Vue
-
@vue/apollo-composable
(since4.0.0-alpha.13
) -
villus
(since1.0.0-beta.8
) -
@urql/vue
(since1.11.0
)
-
-
Others
-
graphql-js
(since15.2.0
) -
graphql-request
(since5.0.0
)
-
You will find demos and code examples for each of them in the examples/front-end/
folder of the codegen repository.
You will also find a complete guide for React and Vue in codegen documentation.
We aim for GraphQL Code Generator 3.0’s client preset to become the official way to generate GraphQL Types for front-end use cases, replacing all existing hook and SDK-based plugins.
For this reason, we encourage you to already give a try at the codegen v3 client
preset (@graphql-codegen/client-presec
) and provide feedback on this issue.
The v3 stable release will be shipped once sufficient feedback is posted.
Finally, while the GraphQL Code Generator 3.0
milestone aims to provide a unified front-end experience through the preset: client
, the 3.x
versions aim to fully rewrite the core packages of codegen.
Some core parts of codegen are more than 6 years old and need to be rewritten (optimized, simplified, and more).
We plan to incorporate the pending issues related to the core packages in this gradual 3.x
milestones.
Introduction of the “community plugins”
Historically, all plugins were pushed to the https://github.com/dotansimha/graphql-code-generator repository, making it hard for us to review all contributions in a reasonable timeframe and to enforce consistency across all the options introduced in the different packages.
We believe that the best way to keep codegen extensible and improve the contribution experience at scale is to introduce the concept of community plugins.
A community plugin offers a feature-set that diverges from the
preset: client
or a plugin created by the community.
Soon, all the existing plugins part of the list below and all the future plugins created by the community will live in their dedicated repository:
-
@graphql-codegen/typescript-react-apollo
-
@graphql-codegen/typescript-graphql-request
-
@graphql-codegen/typescript-apollo-angular
-
@graphql-codegen/typescript-apollo-client-helpers
-
@graphql-codegen/typescript-react-query
-
@graphql-codegen/typescript-urql
-
@graphql-codegen/named-operations-object
-
@graphql-codegen/urql-introspection
-
@graphql-codegen/flow-resolvers
-
@graphql-codegen/typescript-vue-apollo
-
@graphql-codegen/typescript-rtk-query
-
@graphql-codegen/flow-operations
-
@graphql-codegen/typescript-msw
-
@graphql-codegen/typescript-mongodb
-
@graphql-codegen/typescript-type-graphql
-
@graphql-codegen/jsdoc
-
@graphql-codegen/typescript-vue-urql
-
@graphql-codegen/kotlin
-
@graphql-codegen/typescript-vue-apollo-smart-ops
-
@graphql-codegen/java
-
@graphql-codegen/c-sharp-operations
-
@graphql-codegen/hasura-allow-list
-
@graphql-codegen/typescript-stencil-apollo
-
@graphql-codegen/relay-operation-optimizer
-
@graphql-codegen/typescript-oclif
-
@graphql-codegen/java-resolvers
-
@graphql-codegen/java-apollo-android
All the above plugins will be eligible for repository ownership transfer based on relevant past contributions.
Of course, such a change will come with help from our side:
- We will create a new “Create a plugin” guide that will provide complete information and guidelines (ex: publishing, codegen APIs, adding your plugin to the codegen hub)
- Since each community plugin will live in its own repository, we will provide a proper Github repository template with building and publishing CI tools configured.
What about server-side plugins?
The 3.x
milestones include some work on server-side plugins such as typescript-resolvers
(ex: improving Federation support).
Milestones
Below are the details of the aforementioned plans for the 3.0
and 3.x
milestones.
3.0
-
client
preset- Integrate with most of the GraphQL clients
- [x]
graphql-request
https://github.com/prisma-labs/graphql-request/pull/350/files - [ ] https://github.com/dotansimha/graphql-code-generator/issues/8061
- [ ] Improve TypeScript support in libraries that already support TypedDocumentNode (variables should be required if there are required variables in the operation declaration and optional if there are none)
- [ ] URQL
- [ ] Apollo Client
- [x] React Query (works with
graphql-request
) - [x] SWR (works with
graphql-request
) - [ ] Add support for AWS AppSync client
- [x]
- [x] Fix pending issues on
gql-tag-operation-preset
- [x] canary release: https://github.com/dotansimha/graphql-code-generator/pull/8248
- [x] TypeScript config support
- [x]
documents
preset preconfiguration - [x] opinionated plugins configuration
- [ ] deprecate
gql-tag-operations-preset
in favor of theclient-preset
- [x] examples: https://github.com/dotansimha/graphql-code-generator/pull/8184
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/8413
- Update documentation for front-end/GraphQL clients parts
- [x] Update
graphql-request
docs on their repo - [x] Update Apollo Client docs
- [x] Update URQL docs
- [ ] Update
apollo-angular
docs- → not enough time
- [x] Update SWR GraphQL documentation with a link to codegen doc
- [x] Update
- [x] official release 🚢
- [ ] better TypeScript/VSCode integration
- [ ] create a Github template repository
- [ ] new documentation for creating a plugin
- [ ] + updated contributing guidelines
- [ ] move all community plugins to a dedicated repository
- [ ] move the related issues + communicate about new contribution guidelines
- [ ] Reach out to potential people who want to support
- Integrate with most of the GraphQL clients
3.x
preset: client
improvements
- [ ] Only generate actually used types
- [ ] Support operation minification/compilation? (aka embed/re-invent relay-compiler) https://relay-compiler-repl.netlify.app/
- [ ] Support (parameterized) Fragment Arguments? https://github.com/graphql/graphql-spec/issues/204
- [x] “Client Controlled Nullability” support → https://github.com/dotansimha/graphql-code-generator/pull/8071
- [x] Create a TypedDocumentNode string alternative (TypedString) that does not require GraphQL AST on the Client (should be easily configurable within the preset)
- [x] https://tortilla-hq.slack.com/archives/CCVDM3NCD/p1659508122835199
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7885
- [ ] Refactor
preset: client
to not use the old plugins (get rid of actual core packages)
Future of codegen CLI
- [ ] Better TypeScript config support
- [ ] get typed options (
config
) → WIP 🚧
- [ ] get typed options (
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/8200
- [ ] Allow generating outputs even if there are no documents (so you can still generate the gql function for getting started)
- [ ] Better configuration
- [ ] Performance
- [ ] Remove
graphql
dependency - [ ] Better monorepo support?
- multi-project, etc.
- shareable configs? → (one codegen file versus many)
Back-end code generation issues
We will go over the following typescript-resolvers
and graphql-modules
pending plugins issues:
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/2194
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/3207
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/3619
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/3815
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/3873
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/3958
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/4121
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/4722
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/4739
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/4788
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/4901
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5517
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5841
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5776
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5594
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5646
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5998
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5968
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5964
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6483
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6482
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6443
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6173
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7358
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7373
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7560
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5242
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/5139
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6023
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6851
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/6851
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7123
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7123
- [ ] https://github.com/dotansimha/graphql-code-generator/issues/7671
Will there be support for module augmentation still? 🤔 I really enjoy this feature, but there are some shortcomings like some frameworks don't provide for example useFragment
etc.
Will there be support for module augmentation still? 🤔 I really enjoy this feature, but there are some shortcomings like some frameworks don't provide, for example,
useFragment
etc.
Hi @huv1k!
We are planning to remove the support for module augmentation since it is not working without the associated babel plugin properly set up.
Since not all front-end setups can provide custom babel configuration, we were planning to remove the augmentedModuleName
options and also to simplify the installation flow.
However, this being an RFC, we will take your feedback into account! 👀
Based on your code example, does that mean that the preferred way to consume GraphQL operations is co-location within TS/JS files?
I just migrated a large codebase from Apollo CLI to graphql-codegen v2 and refactored it to move all GraphQL operation definitions to .graphql files (importing only typed documents to pass to Apollo Client), I wouldn't want to have to undo that all over again..
Based on your code example, does that mean that the preferred way to consume GraphQL operations is co-location within TS/JS files?
I just migrated a large codebase from Apollo CLI to graphql-codegen v2 and refactored it to move all GraphQL operation definitions to .graphql files (importing only typed documents to pass to Apollo Client), I wouldn't want to have to undo that all over again..
Hi @franky47,
We are exploring different migration path options; providing a codemod
could be one; however, we have to look at the different setups to migrate from.
What plugins are you currently using?
Hi @charlypoly, here's my codegen.yml
:
overwrite: true
schema: "../backend/schema.graphql"
documents: "src/**/*.graphql"
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/modules/graphql.types.ts:
plugins:
- typescript
- typescript-operations
- typed-document-node
hooks:
afterOneFileWrite:
- prettier --write
I have GraphQL code into .graphql
files, which are parsed by the generator to give me the full schema types (I use them to type props in a React/Next.js app), and typed schemas to pass to Apollo Client, which provides type inference (variables & output), so that TypeScript has my back when matching the data & view layers.
I migrated from a setup where the Apollo CLI generated the TS types from gql
tags co-located with their components in .ts(x)
files, hence my remark that having to go back would be quite annoying.
I really like the typed document plugin, it removed the need to explicitly pass generic arguments to useQuery
and useMutation
, so most of my query/mutation hooks are now one-liners. The only thing that required a bit of refactoring to use those was that their naming convention does not seem to be configurable, so I had to rename all FOO_{QUERY|MUTATION}
to FooDocument
, not a big deal but the name can be confusing sometimes (especially when dealing with domain objects also named "Document").
Hope this helps you see a bit better about my particular use-case.
@franky47, thank you for sharing it!
We are also exploring options to still support .graphql
files, we will keep you updated here.
I think there are some problems with this:
- The generation time has gone way up. It has doubled up infact.
- And I see that there have been duplicate types being generated. The size of the file(s) have also gone way up.
vue 3 and vue graphql v4 problem
but it works when these lines are added
If it is going full TypeDocumentNode way (which I like), is it not better to go with a builder pattern approach. The builder can be full type safe and be generated from the introspection query. Additionally you need to generate the builder only initially and on schema change and not when adding new documents. Some open source projects which apply this principle:
- https://github.com/typed-graphql-builder/typed-graphql-builder (my favorite)
- https://zeus.graphqleditor.com/page/plugins/typedDocumentNode.html
- https://github.com/timkendall/tql
In my opinion this provides best of the worlds. Small bundle size, no watchers necessary on frontend and much faster dev cycle. Additionally the builder can be scoped per context (think about hasura roles or public/private introspection results)
Will there be support for module augmentation still? 🤔 I really enjoy this feature, but there are some shortcomings like some frameworks don't provide, for example,
useFragment
etc.Hi @huv1k! We are planning to remove the support for module augmentation since it is not working without the associated babel plugin properly set up. Since not all front-end setups can provide custom babel configuration, we were planning to remove the
augmentedModuleName
options and also to simplify the installation flow.However, this being an RFC, we will take your feedback into account! 👀
Augmented module is a nice feature for people who don't like having their own source code polluted by/relying on generated code, why not keeping it for those willing to make advanced configuration? (babel plugin is just a one line configuration).
Inspired by what graphql-let does, I personally came up with some kind of hack that generates everything to a fake node_modules/@types
of a monorepo:
schema: path/to/schema.json
documents:
- src/**/*.ts
- src/**/*.tsx
generates:
# app operations are generated inside a fake @types module
../../node_modules/@types/myProject__graphql-client:
preset: gql-tag-operations-preset
presetConfig:
augmentedModuleName: '@myProject/graphql-client'
fragmentMasking:
augmentedModuleName: '@myProject/graphql-client'
hooks:
# here is the ugliest part of the "hack": generating a package.json
afterAllFileWrite:
- "printf '{ \"name\": \"@types/myProject__graphql-client\", \"types\": \"gql.d.ts\" }' > '../../node_modules/@types/myProject__graphql-client/package.json'"
This allows for everything within an app to be transparently imported from a @myProject/graphql-client
(a preconfigured apollo-client module in the monorepo) without ever seeing/dealing with any ugly generated code 😅
Big advantage: I can remove codegen at any time without breaking the code, only losing types!
import { gql, useQuery } from '@myProject/graphql-client'
const MyQuery = gql(`
query MyQuery {
...
}
`)
const MyComponent = () => {
const { loading, data, error } = useQuery(MyQuery)
return <>...</>
}
It would be nice to keep this ability to hide the generated code somewhere.
I really like the new approach with preset: client
. It seems like a big step towards a simpler toolchain with less dependencies. I guess currently the configuration for a custom scalar types is not considered:
config:
overwrite: true
schema: 'http://localhost:8080/v1/graphql'
documents:
- './src/**/*.graphql'
- './src/**/*.svelte'
generates:
src/lib/graphql/new/:
preset: client
config:
strictScalars: true
scalars:
numeric: number
jsonb: Array<any>
bigint: number
uuid: string
timestamptz: string
timestamp: string
generated scalars:
export type Scalars = {
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
bigint: any;
jsonb: any;
numeric: any;
timestamp: any;
timestamptz: any;
uuid: any;
};
I really like the new approach with
preset: client
. It seems like a big step towards a simpler toolchain with less dependencies. I guess currently the configuration for a custom scalar types is not considered:
Hi @grischaerbe,
We restored some config
options in the client
preset, from @graphql-codegen/[email protected]
:
more details in the changelog: https://github.com/dotansimha/graphql-code-generator/releases/tag/release-1665062191991
I really like the new approach with
preset: client
. It seems like a big step towards a simpler toolchain with less dependencies. I guess currently the configuration for a custom scalar types is not considered:Hi @grischaerbe,
We restored some
config
options in theclient
preset, from@graphql-codegen/[email protected]
: more details in the changelog:release-1665062191991
(release)
@charlypoly I use [email protected] with
presetConfig:
augmentedModuleName: "@apollo/client"
namingConvention:
typeNames: change-case#pascalCase
but the generated still gives Claim_Cases_Bool_Exp
instead of ClaimCasesBoolExp
Hi What is the difference between preset: client
and preset: gql-tag-operations-preset
?
https://the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen https://www.the-guild.dev/graphql/codegen/plugins/presets/gql-tag-operations-preset
Hi What is the difference between
preset: client
andpreset: gql-tag-operations-preset
?the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen the-guild.dev/graphql/codegen/plugins/presets/gql-tag-operations-preset
Hi @sonatard,
The client
preset is a wrapper on top of gql-tag-operations-preset
. It's going to deprecate gql-tag-operations-preset
soon, and introduce better integration with GraphQL clients.
React-query example... Isn't strongly typed. data
is any
etc.
React-query example... Isn't strongly typed.
data
isany
etc.
Hi @Faithfinder,
Could you provide more context about which example you are referring to?
The client-preset
provides typed GraphQL operations when React Query is used in combination with a supported GraphQL client (ex: graphql-request@^5
) or when the fetcher is properly typed (as documented in our guide).
React-query example... Isn't strongly typed.
data
isany
etc.Hi @Faithfinder,
Could you provide more context about which example you are referring to? The
client-preset
provides typed GraphQL operations when React Query is used in combination with a supported GraphQL client (ex:graphql-request@^5
) or when the fetcher is properly typed (as documented in our guide).
Just checking out an example you've supplied: https://github.com/dotansimha/graphql-code-generator/tree/v3-preset-front-end/examples/front-end/react/tanstack-react-query
Using twoslash here to demostrate that data
is any, and on request
to demonstrate that yarn install
has been run and types are in place, generally.
Hi @charlypoly / @dotansimha. I'm trying out the client preset and so far it's going well but I'm missing some config options that I could previously set: useTypeImports
, arrayInputCoercion
, immutableTypes
, nonOptionalTypename
. I understand that the preset is being strict about which options are passed along but I'm wondering why that is? Are plugin configs also deliberately disabled?
React-query example... Isn't strongly typed.
data
isany
etc.Hi @Faithfinder, Could you provide more context about which example you are referring to? The
client-preset
provides typed GraphQL operations when React Query is used in combination with a supported GraphQL client (ex:graphql-request@^5
) or when the fetcher is properly typed (as documented in our guide).Just checking out an example you've supplied:
v3-preset-front-end
/examples/front-end/react/tanstack-react-queryUsing twoslash here to demostrate that
data
is any, and onrequest
to demonstrate thatyarn install
has been run and types are in place, generally.
Hi @Faithfinder,
I've moved your discussion to a dedicated bug issue: https://github.com/dotansimha/graphql-code-generator/issues/8516 I couldn't reproduce your issue; let's move forward on a reproduction here.
Hi @charlypoly / @dotansimha. I'm trying out the client preset and so far it's going well but I'm missing some config options that I could previously set:
useTypeImports
,arrayInputCoercion
,immutableTypes
,nonOptionalTypename
. I understand that the preset is being strict about which options are passed along but I'm wondering why that is? Are plugin configs also deliberately disabled?
Hi @joelmukuthu,
useTypeImports
, arrayInputCoercion
are still available to use, as documented here: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue#config-api
The new preset: "client"
reduces the number of available options to recommend best practices of codegen configuration.
We will work this week on refining the list of available options and also, the default values of some.
Love the idea of how the client-preset works in terms of TypedDocumentNode. I'm running into issues integrating into my codegen due to the lack of plugin support along with the preset. I use the add
plugin to import my scalars from a different file (as well as to add a comment to my generated files).
- add:
content: "// This file is automatically generated. See gqlcodegen.yml for details"
- add:
content: "import * as CustomScalars from \"@src/types/scalars\";"
config:
scalars:
Any: CustomScalars.GQLAny
JSONObject: CustomScalars.GQLJSONObject
with the preset i get the following error:
✖ [client-preset] providing
plugins
with `preset: "client" leads to duplicated generated types
Is there a workaround here? I understand wanting to disable plugins due to the one-size-fits-all nature of the preset, but an escape hatch would be nice
Is there a workaround here? I understand wanting to disable plugins due to the one-size-fits-all nature of the preset, but an escape hatch would be nice
Hi @awinograd,
Thank you for bringing this up!
I'll remove the add
from the disallow plugin list.
Hi @awinograd,
Thank you for bringing this up! I'll remove the
add
from the disallow plugin list.
@aradalvand is has been fixed in @graphql-codegen/[email protected]
📦
@charlypoly I think you meant to mention @awinograd and not me :)
Hi @charlypoly I think it's great with the type inference from the query string so that we don't have to import the type def. I have always not liked the importing of hooks with custom names, so I think this is a great way forwards. I've run into a few problems while testing this out in our codebase.
- Sometimes you are just using a fragment to reduce duplicated definitions, not to pass data to a child component. In some cases this fragment lives in the same string as the parent query/fragment. But the generated types masks the selected data from this fragment. I would expect it to be available without using the hook.
- Sometimes, we have a component where we used the Fragment type for a prop, but we use it in a place where the data doesn't come from graphql. What is the suggested solution to pass the data? Currently I just did a type cast to the FragmentType which works but seems a bit hacky.
- If I postfix fragment names with Fragment (like in the docs) the type names don't seem to be deduplicated by default (they will have
FragmentFragment
as postfix). That caused an issue because I had addeddedupeOperationSuffix: true
to my config (just copy pasted from prev. config), because thegql.ts
file was deduped but not thegraphql.ts
file. Also when importing the fragment type, if I want to use it somewhere, I would prefer that it's deduped.
These issues leads me to think that it might be useful to have an option to disable the query masking. Masking seems a bit unnecessary to me when you are using TypeScript anyways, as it doesn't force you to remove data when you don't use it anymore. It basically just checks that you have selected the data in the components fragment. But is there actually any danger in using data that's selected by parent/child components? TypeScript would catch it if we were to remove one of those components and we no longer query the data.
Hi @marco2216,
Thank you for your feedback; we appreciate it! Let me answer your questions.
- Sometimes you are just using a fragment to reduce duplicated definitions, not to pass data to a child component. In some cases this fragment lives in the same string as the parent query/fragment. But the generated types masks the selected data from this fragment. I would expect it to be available without using the hook.
You can disable Fragment Masking by passing the following presetConfig
:
import { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'https://swapi-graphql.netlify.app/.netlify/functions/index',
documents: ['src/**/*.tsx'],
ignoreNoDocuments: true, // for better experience with the watcher
generates: {
'./src/gql/': {
preset: 'client',
presetConfig: {
fragmentMasking: false,
},
plugins: []
}
}
}
export default config
2. Sometimes, we have a component where we used the Fragment type for a prop, but we use it in a place where the data doesn't come from graphql. What is the suggested solution to pass the data? Currently I just did a type cast to the FragmentType which works but seems a bit hacky.
Could you provide an example?
Isn't FragmentType<typeof fragmentDocument>
solving this issue?
3. If I postfix fragment names with Fragment (like in the docs) the type names don't seem to be deduplicated by default (they will have
FragmentFragment
as postfix). That caused an issue because I had addeddedupeOperationSuffix: true
to my config (just copy pasted from prev. config), because thegql.ts
file was deduped but not thegraphql.ts
file. Also when importing the fragment type, if I want to use it somewhere, I would prefer that it's deduped.
The dedupeOperationSuffix: true
should not affect the output since it is not part of the config API option supported by the client-preset
.
Could you share your configuration?
@charlypoly
- Good to know, thanks. But what if I want masking enabled in general but just not for fragments that are defined in the same fragment/query string? Maybe it's possible to parse and check that if it's local to the component, don't mask? Or maybe with a special directive or comment?
- I can cast it to
FragmentType<typeof fragmentDocument>
, but then I lose the type safety on the data that's passed in. I can type cast an empty object to FragmentType<typeof fragmentDocument>. - Used client preset v1.1.1 with this config
First off thanks for keeping it up, guys!
We have a large codebase with files in .graphql
so that support would be great!
Looking at generated files I can say this: it is expensive to have an operation string as a key in documents
object in gql.ts
. Moreover the generated document is suboptimal:
/* eslint-disable */
import * as types from './graphql';
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
const documents = {
"\n fragment WorkplaceReg on ManufactureEmployeeReg {\n id\n workplace {\n id\n name\n quant {\n id\n picking\n name\n }\n }\n checkIn {\n id\n createdAt\n }\n }\n": types.WorkplaceRegFragmentDoc,
"\n query employeeQuants($id: ID!) {\n employee(id: $id) {\n id\n workplaceRegs {\n id\n workplace {\n id\n name\n quant {\n id\n name\n }\n }\n ...WorkplaceReg\n }\n storageWorkerClasses {\n id\n }\n }\n }\n": types.EmployeeQuantsDocument,
};
export function graphql(source: "\n fragment WorkplaceReg on ManufactureEmployeeReg {\n id\n workplace {\n id\n name\n quant {\n id\n picking\n name\n }\n }\n checkIn {\n id\n createdAt\n }\n }\n"): (typeof documents)["\n fragment WorkplaceReg on ManufactureEmployeeReg {\n id\n workplace {\n id\n name\n quant {\n id\n picking\n name\n }\n }\n checkIn {\n id\n createdAt\n }\n }\n"];
export function graphql(source: "\n query employeeQuants($id: ID!) {\n employee(id: $id) {\n id\n workplaceRegs {\n id\n workplace {\n id\n name\n quant {\n id\n name\n }\n }\n ...WorkplaceReg\n }\n storageWorkerClasses {\n id\n }\n }\n }\n"): (typeof documents)["\n query employeeQuants($id: ID!) {\n employee(id: $id) {\n id\n workplaceRegs {\n id\n workplace {\n id\n name\n quant {\n id\n name\n }\n }\n ...WorkplaceReg\n }\n storageWorkerClasses {\n id\n }\n }\n }\n"];
export function graphql(source: string): unknown;
export function graphql(source: string) {
return (documents as any)[source] ?? {};
}
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;
What can be improved: every source is triplicated (repeated in 3 places): in document key and graphql(source: __here__)(typeof documents):[__here__]
Assign it to a constant with the name of the Fragment of Query etc and you get a reduced file (bundle) size.
You may easily extract the query/mutation/fragment name and use it as an inferred type and the key in documents, like so without any need of overloading graphql
function type:
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
/* eslint-disable */
import * as types from './graphql';
const documents = {
'WorkplaceReg': types.WorkplaceRegFragmentDoc,
'employeeQuants': types.EmployeeQuantsDocument,
};
type DocumentKey = keyof typeof documents;
type OperationType = 'query' | 'fragment' | 'mutation' | 'subscription';
type GenericDeclaration<T extends string, V extends OperationType> = V extends 'fragment'? `\n ${V} ${T} on ${string}`:`\n ${V} ${T}${'(' | ' on' | ' {'}${string}`;
export function graphql<T extends string, V extends OperationType>(
source: GenericDeclaration<T, V>,
): T extends DocumentKey ? typeof documents[T] : never {
// use a different approach (regex?) as to extract the name that corresponds to T
const extractedName:T = pseudoFn()
return (documents)[extractedName] ?? {};
}
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode<
infer TType,
any
>
? TType
: never;
Secondly you stated that this approach is better than plugins with sdk generators. Well, it is not! you have the documents
constants which is no different than what the typescript-generic-sdk plugin we wrote does - it stores all document nodes json in one big object which cannot be tree shaken. If I'm wrong, I'm happy to be corrected. Actually if you look up the plugin in your repo - we took the approach of using operation names instead of operation string code. It's up to the dev to make sure his methods are unique in naming. We have a huge graphql scheme and didn't have any naming collisions so far.
Yeah and lastly fragmentMasking: false,
is not listed in the link you provided above