Comments (14)
For my project, I wrote a rollup plugin based on babel plugin that replaces the source code of graphql queries with generated code. This way tree-shaking graphql.ts is completely eliminated. It is also important to enable enumsAsTypes: true
in the code generator settings
from graphql-code-generator.
Ah, thats interesting. We'd probably need to complicate the API to solve for that - like adding an additional method for registering fragments. But that's getting complicated:
const A = graphql.fragment(`
fragment A on Query {
a
}
`)
const B = graphql.fragment(`
fragment B on Query {
...A
}
`, [A])
const Query = graphql(`
query {
...A
...B
}
`, [A, B])
// implementation (ignoring typescript validation for the moment)
const fragStore = [];
function getFragmentsFromDeps(deps: string[]) {
return fragStore
.filter(frag => deps.includes(frag.fragAndDeps))
.map(frag => frag.fragment)
}
export function graphql(source: string, fragments: string[] = null) {
if (Array.isArray(fragments) && fragments.length > 0) {
const frags = getFragmentsFromDeps(fragments);
// dedupe frags, and combine with source
return [...new Set(frags), source].join("\n");
} else {
return source;
}
}
graphql.fragments = (fragment: string, deps: string[] = null) => {
const fragAndDeps = (Array.isArray(deps))
? [...new Set(getFragmentsFromDeps(deps)), fragment].join("\n")
: fragment;
fragStore.push({ fragment, deps, fragAndDeps });
return fragAndDeps; // I assume this needs to return the aggregated string for type gen to work
}
I didn't test any of that (there may be some cases where we need to recurse on the deps array - I'm not sure, would need to write some unit tests), but the idea would be to store enough info about the registered fragment, that we can reconstruct the correct query package later.
I don't know what impact that would have on type generation side of things, but on the runtime this would work, because the package resolver would make sure to include all of the necessary linked fragments in the correct order, as long as they properly specified in the deps arrays.
It should be possible to support even trickier cases like:
const A = graphql(`
fragment A on Query {
a
}
`)
const B = graphql(`
fragment B on Query {
...A
}
`, [A])
const Query = graphql(`
query {
...B
}
`, [B])
As far as typescript errors - yeah, that's an issue. We'd need some way to validate that, maybe an eslint rule? Again, adding more complexity...
from graphql-code-generator.
By doing this globally referenced fragments could no longer be used within the GraphQL operation strings.
from graphql-code-generator.
Hmm, I didn't consider fragments. Can you show me an example? I'd like to see if I can work out a pattern that would support that.
from graphql-code-generator.
graphql-code-generator/examples/react/apollo-client/src/App.tsx
Lines 8 to 18 in c720b1b
from graphql-code-generator.
I added a global fragment to my playground, and ran the generator - it doesn't look like it does anything all that different from including any other query. It doesn't seem like anything else uses the documents
object, which is the thing I want to get rid of. I think this would still work as expected:
import * as types from "./graphql";
type QueryMap = {
"fragment UserFields on User { name }": typeof types.UserFieldsFragmentDoc
"query GetUser($id: ID!) { user(id: $id) { ...UserFields } }": typeof types.GetUserDocument,
"query GetUsername($id: ID!) { user(id: $id) { username } }": typeof types.GetUsernameDocument,
};
// Overloaded function signatures
export function graphql<TSource extends keyof QueryMap>(source: TSource): QueryMap[TSource];
export function graphql(source: string): unknown;
// Function implementation
export function graphql(source: string) {
return source;
}
Am I missing some other type of output?
from graphql-code-generator.
Yeah, if the graphql
function only returns the parameter passed to it:
export function graphql(source: string) {
return source;
}
That string does not contain the fragment definition, thus when the string is sent to the server, the GraphQL execution will fail.
In addition to that, features like persisted documents will no longer work without the lookup map/babel/swc plugin.
from graphql-code-generator.
Got it. So you still need some kind of runtime lookup system, at least for fragments.
it's just that the map is huge, and the babel/swc plugins either don't work at all (swc) in nextjs, or don't seem to do much even if you get it to work (babel) in nextjs
(And SWC produces smaller chunks - so you actually overall lose budget if you use babel vs swc in next.js - even if I can get the graphql map size down to essentially 0)
from graphql-code-generator.
The Babel plugin works perfectly for us. SWC has known issues.
We are happy for suggestions on alternative approaches, but right now I am afraid the lookup map (by default) is the only solution that does not force people to use the plugins.
from graphql-code-generator.
Heck, I'd be happy with a solution that does what I've proposed, maybe hidden behind a setting in codegen.ts, even if it breaks global Fragments.
To me, this isn't terrible:
import { graphql } from "data/types/gql";
import ReportFieldsFragment from "data/fragments/ReportFieldFragment";
export default graphql(`
${ReportFieldsFragment}
query reports($order: [Core_EditionSortInput!]) {
core_reports(order: $order) {
...ReportFields
}
}
`);
I don't use persisted queries (without APQ anyway), so that's fine.
from graphql-code-generator.
We could consider passing the fragments as an array parameter to the graphql function, then the graphql function could just concatenate the strings. π€
export default graphql(`
query reports($order: [Core_EditionSortInput!]) {
core_reports(order: $order) {
...ReportFields
}
}
`, [ReportFieldsFragment]);
But, this could then cause issues where the same fragment is printed twice in the operation sent to the server because it was referenced within two or more fragments referenced by a query/mutation/subscription operation.
That would open a whole new deduplication rabbit-hole.
from graphql-code-generator.
You could dedupe that array pretty easily. What I'm wondering is if there is some pattern on the other side (in gql.ts) we could use to insert the same (deduped) array, without too much overhead. Even something like a hybrid solution, where global fragments are defined the old way, and queries are defined the new way. I'll play with it more later.
from graphql-code-generator.
Had to teach some karate classes, I'm back. I actually think your array solution would work nicely. There shouldn't be deduplication issues - if the Fragment is in the array once, it would only be included in the query package once. Should be pretty straight forward. Similar to the way I did it, without the use of template strings.
Function Implementation:
export function graphql(source: string, fragments: string[] = null) {
if (Array.isArray(fragments) && fragments.length > 0) {
return [...fragments, source].join("\n");
} else {
return source;
}
}
from graphql-code-generator.
@CaptainN this solution won't work if a fragment is referenced by multiple fragments. You will end up with duplicated fragment definitions in the document string, which then will be rejected by the GraphQL server.
const A = graphql(`
fragment A on Query {
a
}
`)
const B = graphql(`
fragment B on Query {
...A
}
`, [A])
const Query = graphql(`
query {
...A
...B
}
`, [A, B])
Also, you will get no typescript compiler/codegen error if a fragment was not passed, but is required as it is used within that operation document.
from graphql-code-generator.
Related Issues (20)
- [Severity Vulnerability] - Uncontrolled resource consumption in package "braces" HOT 2
- #9962 causes issues with our schema: parts of the types in ResolversType map contradict other parts of the type (repro) HOT 8
- `InputMaybe` should explicitly include `undefined` HOT 4
- Disable fragmentMasking not working HOT 1
- Configure conditional directives
- Redundant suffix when handling anonymous operation names with user-provided `namingConvention` function
- Print missing dependency warnings for filetypes even if supported files match
- `ClientSideBaseVisitor.fragmentsGraph` is recomputed several times despite never changing HOT 2
- Supporting gql tag functions
- `documentMode: βstringβ` produces types incompatible with strict typescript
- [Bug] codgen creates invalid operations when queries include fragment definitions
- `verbatimModuleSyntax:true` in tsconfig.json causes generated files to fail type validation HOT 2
- Input fields with defaults should be optional for client and fields without defaults should not
- Map of operations implicitly has type `any[]` when no operations are found
- suggestion for handling resolved types HOT 1
- Installed with `relay-compiler` will cause `npm i -D relay-compiler@latest` to install v12 HOT 1
- Codegen CLI in watch mode doesn't respect "silent" configuration
- Broken linter on repo since eslint 9 update
- Option to Generate Strong TypeScript Client with separated TS files
- client-preset generates imports incompatible with moduleResolution=node16
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphql-code-generator.