Add an @inline direction in client-preset to unmask actual GraphQL fragments
Is your feature request related to a problem? Please describe.
A user may have prior-existing fragments, or want to use fragments, that are not 1:1 directly associated with a specific component. For example:
fragment User {
id
name
...
}
query {
user(...) {
...User
}
}
With the current fragment masking in client-preset, these fragments are assumed to be components, which will then fail to work.
Describe the solution you'd like
My suggestion is to mirror how Relay is designed, with an @inline or @relay(mask: false) directive. This directive indicates that a fragment is not a component's fragment and allows intermixing of actual fragments with component fragments:
query {
user(...) {
...UserAvatar_User
...User @inline
}
}
this will expand the User fragment, but continue to mask the UserAvatar_User fragment (which might itself want to expand the User fragment)
Describe alternatives you've considered
One alternative is to simply suggest that fragments themselves are an antipattern because repeated GraphQL entire objects should be abstracted to a component. I think this is an unrealistic approach, especially when considering transitioning onto fragment masking from an existing codebase.
Is your feature request related to a problem? Please describe.
No response
I believe it could be related to https://github.com/dotansimha/graphql-code-generator/issues/9075, which describes an incremental adoption of fragment masking via a type utility to unmask a fragment.
Unmasking specific fragments via a directive is an option I like, and I wasn't thinking about!
Regarding the alternative mentioned, I do believe that it is an anti-pattern to create a single fragment shared across many containers, but I also recognize the fact that, in some particular cases, this would be super useful.
@charpeni I think this is tangential, but if I'm not mistaken it has to be defined at the directive level (or at least, not at the Typescript level) to resolve this problem. This is because the fragment problem here is caused at the point of codegen, so we never get up to the point of Typescript at all to begin with.
My reading of #9075 is that an existing working codebase will need dramatic updates to update to fragment masking because you need to write every mask at once in order for it to work; the codegen works, but then each component isn't actually getting the props it thought it would
Though these could be consolidated by suggesting that the migrating user adds @inline to every fragment and then slowly removes them as they build the mask fragments 🤷
This would also solve sharing a fragment between query and mutation (https://github.com/dotansimha/graphql-code-generator/discussions/9325) and also for cache updates (especially new additions where a fragment is needed)
Some prior art: gql.tada supports an @_unmask directive much like this suggestion. https://gql-tada.0no.co/guides/fragment-colocation#fragment-masking
This seems similar to Apollo's @unmask https://github.com/dotansimha/graphql-code-generator/pull/10163 🙂
If anyone has some time to create a PR, I'm happy to collab to move it over the line