Open theguild-bot opened 2 years ago
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:
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:
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/client-preset@1.0.4
:
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/client-preset@1.0.4
: more details in the changelog:release-1665062191991
(release)
@charlypoly I use client-preset@1.0.5 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/client-preset@1.1.1
📦
@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.
FragmentFragment
as postfix). That caused an issue because I had added dedupeOperationSuffix: true
to my config (just copy pasted from prev. config), because the gql.ts
file was deduped but not the graphql.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
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 FragmentTypeFirst 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
An one more thing: +1 to generating the types for the scheme and importing them into the graphql.ts
thus making the external. In a superapp (in a monorepo) that imports micro-frontends and they all reflect against the same backend-served schema it's better to have enums and everything else deduped
I am getting some duplicate fragment errors from the apollo-server backend with the new graphql tag that I wasn't getting with the tag from graphql-tag.
I am using these fragments in multiple different fragments, but I would expect them to get deduplicated or something?
Hi @charlypoly, thanks for responding to my earlier question. While working with fragments, types don't work with something like this:
const userFragment = graphql(`
fragment User_user on User {
firstName
lastName
}
`);
const query = graphql(`
{
user(id: 5) {
...User_user
}
}
${userFragment}
`);
And that's because the string that the generated code expects is something like this:
const generatedQueryString = `
{
user(id: 5) {
...User_user
}
}
# empty line here
`;
While it's possible to avoid the empty line by formatting the query a different way, I think this is still a case that should be handled by the code generator. Alternatively, using operation names instead of the query/mutation/fragment strings (as suggested by jahglow) could also work around this.
I think it is better if you can create new issues for your bug reports or feature requests :) This issue belongs to the roadmap.
I am getting some duplicate fragment errors from the apollo-server backend with the new graphql tag that I wasn't getting with the tag from graphql-tag. I am using these fragments in multiple different fragments, but I would expect them to get deduplicated or something?
Hi @marco2216, Please refer to the dedicated issue where a solution has been suggested: https://github.com/dotansimha/graphql-code-generator/issues/8103
While working with fragments, types don't work with something like this:
Hi @joelmukuthu,
Fragment documents should not be included in the Query string, you will find more details here: https://stackoverflow.com/questions/74068078/the-query-is-always-of-type-unknown-when-created-with-graphql-codegen
- 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 theclient-preset
.
@marco2216 let's continue the discussion here: https://github.com/dotansimha/graphql-code-generator/discussions/8554#discussioncomment-4026197
Hi all!
As the client-preset
is getting more usage, we are looking for feedback regarding its config options and defaults: https://github.com/dotansimha/graphql-code-generator/issues/8562
Hi. I am a developer of a preset. https://github.com/kazekyo/nau https://www.naugraphql.com/docs/introduction
This preset is like relay-operation-optimizer, enabling the use of Relay directives such as @argumentDefinitions
, @refetchable
, and @appendNode
, etc.
I want to allow the users who are currently using my preset to use the new client
preset naturally in v3, so I would like to provide my features as a plugin instead of the preset.
But there are still things that I cannot provide within the current limitation of plugin. 😢
I need a feature to change documents before executing plugins. It is similar to addToSchema
. It is necessary for the implementation of @arguments
and @argumentDefinitions
, etc.
I also want to use the original documents to execute my plugin, meaning I want to write the following plugin:
module.exports = {
plugin(schema, documents, config, context) {
return generateMyCode(schema, documents, context.myPlugin.originalDocuments);
},
changeDocuments(schema, documents, config) {
const newDocuments = myChangeDocumentsFunction(documents);
return { documents: newDocuments, context: { myPlugin: { originalDocuments: documents } } };
},
};
Can you please consider extending the plugin's design to solve these problems? I would be happy to provide ideas or help with implementation if you can consider it. 🙌
unless I'm missing something, you cannot currently write something like this using the client preset:
import { gql } from '@apollo/client/core'
import { graphql } from './generated'
const myQuery = graphql(gql`
query MyQuery {
me {
name
}
}
`)
IMO this is the most idiomatic way people define graphql documents inline with code, and it's a bit... optimistic to consider any example documentation complete when it was done by avoiding using gql
tag and instead using /* GraphQL */
followed by a regular template string. As it currently stands, you cannot use Apollo GraphQL VS Code features such as intellisense while writing your inline document.
This issue seems to indicate Typescript will not support this kind of interface
Hi. I am a developer of a preset. kazekyo/nau naugraphql.com/docs/introduction
This preset is like relay-operation-optimizer, enabling the use of Relay directives such as
@argumentDefinitions
,@refetchable
, and@appendNode
, etc.I want to allow the users who are currently using my preset to use the new
client
preset naturally in v3, so I would like to provide my features as a plugin instead of the preset. But there are still things that I cannot provide within the current limitation of plugin. 😢I need a feature to change documents before executing plugins. It is similar to
addToSchema
. It is necessary for the implementation of@arguments
and@argumentDefinitions
, etc. I also want to use the original documents to execute my plugin, meaning I want to write the following plugin:module.exports = { plugin(schema, documents, config, context) { return generateMyCode(schema, documents, context.myPlugin.originalDocuments); }, changeDocuments(schema, documents, config) { const newDocuments = myChangeDocumentsFunction(documents); return { documents: newDocuments, context: { myPlugin: { originalDocuments: documents } } }; }, };
Can you please consider extending the plugin's design to solve these problems? I would be happy to provide ideas or help with implementation if you can consider it. 🙌
Hi @kazekyo,
It's a really nice preset! 🚀
Regarding your core API change request, we end up adding a similar API for the new client-preset
:
Would this match your needs?
IMO this is the most idiomatic way people define graphql documents inline with code, and it's a bit... optimistic to consider any example documentation complete when it was done by avoiding using
gql
tag and instead using/* GraphQL */
followed by a regular template string. As it currently stands, you cannot use Apollo GraphQL VS Code features such as intellisense while writing your inline document.
This topic is currently being discussed on the following discussion: https://github.com/dotansimha/graphql-code-generator/discussions/8584
For now, due to TypeScript limitations, client-preset
cannot support the gql
template literal syntax.
IMO this is the most idiomatic way people define graphql documents inline with code, and it's a bit... optimistic to consider any example documentation complete when it was done by avoiding using
gql
tag and instead using/* GraphQL */
followed by a regular template string. As it currently stands, you cannot use Apollo GraphQL VS Code features such as intellisense while writing your inline document.This topic is currently being discussed on the following discussion: #8584
For now, due to TypeScript limitations,
client-preset
cannot support thegql
template literal syntax.
Understood @charlypoly -- see #8591 for an alternative proposal that is possible with Typescript and only a slight difference from currently available behavior when using plugins instead of client preset
Hi. I am a developer of a preset. kazekyo/nau naugraphql.com/docs/introduction This preset is like relay-operation-optimizer, enabling the use of Relay directives such as
@argumentDefinitions
,@refetchable
, and@appendNode
, etc. I want to allow the users who are currently using my preset to use the newclient
preset naturally in v3, so I would like to provide my features as a plugin instead of the preset. But there are still things that I cannot provide within the current limitation of plugin. 😢 I need a feature to change documents before executing plugins. It is similar toaddToSchema
. It is necessary for the implementation of@arguments
and@argumentDefinitions
, etc. I also want to use the original documents to execute my plugin, meaning I want to write the following plugin:module.exports = { plugin(schema, documents, config, context) { return generateMyCode(schema, documents, context.myPlugin.originalDocuments); }, changeDocuments(schema, documents, config) { const newDocuments = myChangeDocumentsFunction(documents); return { documents: newDocuments, context: { myPlugin: { originalDocuments: documents } } }; }, };
Can you please consider extending the plugin's design to solve these problems? I would be happy to provide ideas or help with implementation if you can consider it. 🙌
Hi @kazekyo,
It's a really nice preset! 🚀
Regarding your core API change request, we end up adding a similar API for the new
client-preset
:Would this match your needs?
@charlypoly This API may be different from what I need. I think we need some more discussion. 🙏 I have created a discussion. https://github.com/dotansimha/graphql-code-generator/discussions/8593 I would be happy to discuss it there. 😃
Anyway, I'm really looking forward to v3! 🚀
Hello team, great work, love it! Question:
Create a TypedDocumentNode string alternative (TypedString) that does not require GraphQL AST on the Client (should be easily configurable within the preset)
Does this mean that it would be a goal to output the original GraphQL string instead of a document when generating things?
If so, that would be wonderful. (Is it currently possible but just not part of the client preset yet? Or just not possible at all right now?)
We've had issues in the past because of the GraphQL AST parser slowing down our websites, so we've had to pass on using GraphQL code generator for the time being. However, if we could get all the automatically-typed goodness, but without graphql-tag / GraphQL AST parsing at runtime, that would be great. (For context, we're using Remix, which uses ESBuild, so we can't use any of the listed preprocessing tricks either)
Or maybe I'm missing something and this is all possible already? Forgive me if that's true.
Thanks!
Hello team, great work, love it! Question:
Create a TypedDocumentNode string alternative (TypedString) that does not require GraphQL AST on the Client (should be easily configurable within the preset)
Does this mean that it would be a goal to output the original GraphQL string instead of a document when generating things?
If so, that would be wonderful. (Is it currently possible but just not part of the client preset yet? Or just not possible at all right now?)
We've had issues in the past because of the GraphQL AST parser slowing down our websites, so we've had to pass on using GraphQL code generator for the time being. However, if we could get all the automatically-typed goodness, but without graphql-tag / GraphQL AST parsing at runtime, that would be great. (For context, we're using Remix, which uses ESBuild, so we can't use any of the listed preprocessing tricks either)
Or maybe I'm missing something and this is all possible already? Forgive me if that's true.
Thanks!
@frehner exactly, basically we can bake in the type into anything. Here is a quick example.
import {DocumentNode} from "graphql"
type WithSignature<TResult, TVariables> = {[" __baked_in_types"]?: (v: TVariables) => TResult }
type ThingWithBakedInType<T, TResult = Record<string, unknown>, TVariables = Record<string, never>> = T & WithSignature<TResult, TVariables>
type TypedString<TResult, TVariables> = ThingWithBakedInType<string, TResult, TVariables>
declare function fetch<TResult, TVariables>(foo: ThingWithBakedInType<unknown, TResult, TVariables>): TResult
declare let foo: TypedString<{a: 1}, {b: 2}>
declare let foo2: ThingWithBakedInType<DocumentNode, {c: 3}>
fetch(foo).a
fetch(foo2).c
Links
With fragmentMasking: false
, I thought we were supposed to be using the generated fragment types; but it seems these are in graphql.ts
and not re-exported from index.ts
. Is this just an oversight, or is there some other way we should be getting back our fragment types? (Obviously we can deep import, but I am assuming index.ts
is supposed to be our interface to the generated code.)
I also hope .graphql
file support is still being considered; the const someName = graphql(/* GraphQL */`query SomeOtherName { ... }`)
pattern is a real eyebrow-raiser that we're frankly not interested in adopting. We would rather keep our GraphQL in GraphQL files and avoid this confusing syntax if possible.
thanks for building this! i'm glad i can use some of the same patterns available in relay with graphql-codegen now
@charlypoly do you have any thoughts on supporting generating multiple files vs single gql.ts
/graphql.ts
files that contains the runtime nodes for all document definitions?
in a project with a large amount of definitions i would like to be able to not load all of the runtime document nodes upfront unless they're actually being used, and let code-splitting and the bundler just include the ones that are needed.
I noticed that the implementation of the generated graphql
function relies on having the documents
map to be able to return the corresponding runtime node for a document, but maybe this could work similarly to the relay compiler where the graphql
call gets transpiled into an import/require call that imports the corresponding generated file for that document, which would contain the appropriate document node?
alternatively, is there a recommended way to customize the output of the client-preset
, maybe to do a custom implementation of this sort of capability?
in a project with a large amount of definitions i would like to be able to not load all of the runtime document nodes upfront unless they're actually being used, and let code-splitting and the bundler just include the ones that are needed.
Hi @jstejada,
The client-preset
comes with a Babel plugin to address this concern.
It is not documented yet but you can find a working example here: https://github.com/dotansimha/graphql-code-generator/tree/master/examples/front-end/advanced/babel-optimized
@charlypoly oh that’s perfect, thank you!
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:
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:
near-operation-file
compatibility)To make GraphQL code generation great and simple, the v3 version will introduce two major changes:
Here is how you can already configure codegen for all GraphQL Clients:
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:First, start GraphQL Code Generator in watch mode:
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):
Thanks to work made to integrate
TypeDocumentNode
(the underlying plugin used bypreset: 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:graphql()
function needs to be imported (no type, hooks, document imports)Finally, this new
preset: client
has been properly tested on all popular GraphQL clients across most frameworks:@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
(withgraphql-request@5.0.0
)swr
(withgraphql-request@5.0.0
)@urql/exchange-graphcache
(since3.1.11
)@urql/svelte
(since1.1.3
)@vue/apollo-composable
(since4.0.0-alpha.13
)villus
(since1.0.0-beta.8
)@urql/vue
(since1.11.0
)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 thepreset: client
, the3.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.
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:
What about server-side plugins?
The
3.x
milestones include some work on server-side plugins such astypescript-resolvers
(ex: improving Federation support).Milestones
Below are the details of the aforementioned plans for the
3.0
and3.x
milestones.3.0
client
presetgraphql-request
https://github.com/prisma-labs/graphql-request/pull/350/filesgraphql-request
)graphql-request
)gql-tag-operation-preset
documents
preset preconfigurationgql-tag-operations-preset
in favor of theclient-preset
graphql-request
docs on their repoapollo-angular
docs3.x
preset: client
improvementspreset: client
to not use the old plugins (get rid of actual core packages)Future of codegen CLI
config
) → WIP 🚧graphql
dependencyBack-end code generation issues
We will go over the following
typescript-resolvers
andgraphql-modules
pending plugins issues: