Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TypedDocumentNode string alternative #9137

Merged
merged 35 commits into from
Mar 21, 2023
Merged

Conversation

beerose
Copy link
Contributor

@beerose beerose commented Mar 8, 2023

🚨 Depends on a PR in graphql-typed-document-node

Description

Related to: #8296:
CleanShot 2023-03-09 at 14 46 45@2x

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Screenshots/Sandbox (if appropriate/relevant):

Adding links to sandbox or providing screenshots can help us understand more about this PR and take action on it as appropriate

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test A
  • Test B

Test Environment:

  • OS:
  • @graphql-codegen/...:
  • NodeJS:

Checklist:

  • I have followed the CONTRIBUTING doc and the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2023

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
@graphql-codegen/cli 3.3.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/visitor-plugin-common 3.1.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/typescript-document-nodes 3.0.3-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/gql-tag-operations 3.0.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/typescript-operations 3.0.3-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/typescript-resolvers 3.2.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/typed-document-node 4.0.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/typescript 3.0.3-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/client-preset 3.0.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/gql-tag-operations-preset 3.0.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/graphql-modules-preset 3.1.2-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎
@graphql-codegen/plugin-helpers 4.2.0-alpha-20230321125704-a86f4bcb9 npm ↗︎ unpkg ↗︎

@changeset-bot
Copy link

changeset-bot bot commented Mar 8, 2023

🦋 Changeset detected

Latest commit: a86f4bc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@graphql-codegen/client-preset Major
@graphql-codegen/typed-document-node Major
@graphql-codegen/gql-tag-operations Major
@graphql-codegen/gql-tag-operations-preset Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2023

💻 Website Preview

The latest changes are available as preview in: https://f9b2e87e.graphql-code-generator.pages.dev

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we want a new example or just modify an existing one?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think urql is not a good example because it actually requires the AST at runtime anyways 🤔 .
We can add or modify a react-query or similar example that does not require the AST.
What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think urql is not a good example because it actually requires the AST at runtime anyways

Does it, though? It accepts both string and AST and seems to work fine (I modified the original urql example). Unless I'm missing something.

Regarding the react-query example — it currently uses @graphql-tools/executor-http, but I could replace it with fetch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, urql uses graphql internally and thus will just parse the string to the ast at runtime

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I am fine with replacing executor HTTP in react-query!

Comment on lines 4 to 5
dependencies updates:
- Updated dependency [`@graphql-typed-document-node/[email protected]` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.2.0) (from `3.1.2`, in `dependencies`)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: update with the latest version when a PR to @graphql-typed-document-node/core is accepted and released

Comment on lines -48 to -50
if (config && config.documentMode === DocumentMode.string) {
throw new Error(`Plugin "typed-document-node" does not allow using 'documentMode: string' configuration!`);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this

@@ -26,7 +26,7 @@
"@graphql-codegen/gql-tag-operations": "2.0.2",
"@graphql-codegen/plugin-helpers": "^4.1.0",
"@graphql-codegen/visitor-plugin-common": "^3.0.2",
"@graphql-typed-document-node/core": "3.1.2",
"@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

@beerose beerose marked this pull request as ready for review March 13, 2023 10:32
@n1ru4l
Copy link
Collaborator

n1ru4l commented Mar 13, 2023

I think we will also have issues with metadata within the string document mode 🤔 #8757

Any idea how we could still support metadata with strings? Maybe instead we should export an object with a string (operations string key) and a meta object?

Also I saw that we embed fragments with ... here, would this cause the same issues as mentioned/fixed by #8971 for document nodes?

@beerose
Copy link
Contributor Author

beerose commented Mar 13, 2023

Also I saw that we embed fragments with ... here, would this cause the same issues as mentioned/fixed by #8971 for document nodes?

Done Yeah, good point. Will work on that.

I think we will also have issues with metadata within the string document mode 🤔 #8757

Yep. Will work on that too. Exporting an object sounds good — I don't really have other ideas right now except for class MyString extends String which seems a bit ugly 😅

Edit: after thinking about it for a bit, I realised that the class may be a good solution here (even if ugly 😅). I'm thinking about something like this:

import { DocumentTypeDecoration } from '@graphql-typed-document-node/core';

export type TypedDocumentString<TResult, TVariables> = DocumentTypeDecoration<TResult, TVariables> & string;

class DocumentStringWithMeta<TResult, TVariables>
  extends String
  implements DocumentTypeDecoration<TResult, TVariables>
{
  __apiType?: DocumentTypeDecoration<TResult, TVariables>['__apiType'];

  constructor(value: string, public __meta__: { hash: string }) {
    super(value);
  }
}

const _a = new DocumentStringWithMeta(`
  query {
    ids
  }
`,
  { hash: '123' }
);

const meta = _a.__meta__.hash;

Now a question is — should we only use DocumentStringWithMeta with persisted documents, or maybe we always want to use this (and hence kinda advertising persistent documents as a default practice)?

Also, I'm not sure if @graphql-typed-document-node/core is the best place for that — maybe we can inline this class in the generated file?

Are there any other things like that (things that would cause problems with string documents)? I guess it would be a good idea to extend the tests (or some of them) to also run in "string" document mode. What do you think, @n1ru4l?

@github-actions
Copy link
Contributor

github-actions bot commented Mar 15, 2023

diff --git a/website/algolia-lockfile.json b/website/algolia-lockfile.json
index 86c85dfcb..9596c78cf 100644
--- a/website/algolia-lockfile.json
+++ b/website/algolia-lockfile.json
@@ -2043,7 +2043,8 @@
       "Config API",
       "Fragment Masking",
       "Persisted documents",
-      "Reducing bundle size: Babel plugin"
+      "Reducing bundle size: Babel plugin",
+      "DocumentMode"
     ],
     "toc": [
       {
@@ -2109,6 +2110,17 @@
         ],
         "title": "Reducing bundle size: Babel plugin",
         "anchor": "reducing-bundle-size-babel-plugin"
+      },
+      {
+        "children": [
+          {
+            "children": [],
+            "title": "When to use a string DocumentMode?",
+            "anchor": "when-to-use-a-string-documentmode"
+          }
+        ],
+        "title": "DocumentMode",
+        "anchor": "documentmode"
       }
     ],
     "content": "d41d8cd98f00b204e9800998ecf8427e",

@beerose beerose requested a review from saihaj March 20, 2023 11:39
Comment on lines -3 to +8
export type FragmentType<TDocumentType extends DocumentNode<any, any>> = TDocumentType extends DocumentNode<
infer TType,
any
>
? TType extends { ' $fragmentName'?: infer TKey }
? TKey extends string
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> =
TDocumentType extends DocumentTypeDecoration<infer TType, any>
? TType extends { ' $fragmentName'?: infer TKey }
? TKey extends string
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
: never
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this considered a breaking change for the codegen or not? @n1ru4l @saihaj

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, people shouldn't use this type with anything else than our generated stuff.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed should be fine

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, as I think about it a bit more, this change kinda requires people to upgrade their typed document node version. 🤔

In graphql-yoga we treat peerDependency upgrades depending on the type of change.

e.g.
X.1.1 bump of a peer dependency would be a breaking change
1.X.1 bump of a peer dependency would be a minor change
1.1.X bump of a peer dependency would be a patch change

So I think we should treat this the same here (minor change).

Here the special case is that it is not listed as a peer dependency, but theoretically, it could be one, as people will need to install it, otherwise, their code won't compile with strict package manages like pnpm and yarn that do no hoisting. 🤔

Then, however, whether it should be a peer dependency or not also depends on the location where the code is generated.

So the safest option would be to ship this as a breaking change. I am sure people will open issues if we don't...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants