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

feat: Add stripIgnoredCharacters option (visitor-plugin-common) - continued #8489

Closed
wants to merge 3 commits into from

Conversation

JanStevens
Copy link

Description

Adds a new stripIgnoredCharacters: boolean option to client-side-base-visitor that removes redundant characters (like line-breaks, whitespaces, etc.) from the query strings.

In the linked issue, I originally proposed doing .replace(/\s+/g, ' ').trim() on the strings, but that turned out to be an unreliable approach as it would fail to cover a number of cases:

  • It doesn't remove extraneous whitespaces that are not consecutive, so like query ( $var : Int! ) (should become query ($var: Int!)) or more commonly query { foo bar } (should become query{foo bar}).
  • If you have a string literal inside the query, that contains more than one consecutive space or line breaks, it removes those but it obviously shouldn't.

This all means a GraphQL-specific minifier is actually needed to do this reliably,
Happily I found out there's a built-in function in graphql-js for this very task! stripIgnoredCharacters — see graphql/graphql-js#1523, which does precisely this.

Related # (issue)

Related to #5616 and continuation of #8322

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

  • I've added a test in ts-documents.spec.ts, but I'm not really sure this is the best location. I looked at how other options are tested but it seems there are barely any tests for the client visitor.

Test Environment:

  • OS: Mac M1
  • @graphql-codegen/...: latest
  • NodeJS: v16.18

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

This is the continuation of PR #8322 all credits go to @aradalvand

@changeset-bot
Copy link

changeset-bot bot commented Oct 17, 2022

🦋 Changeset detected

Latest commit: 37d7dba

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

This PR includes changesets to release 46 packages
Name Type
@graphql-codegen/visitor-plugin-common Major
@graphql-codegen/flow Patch
@graphql-codegen/flow-operations Patch
@graphql-codegen/flow-resolvers Patch
@graphql-codegen/java-apollo-android Patch
@graphql-codegen/java-common Patch
@graphql-codegen/java Patch
@graphql-codegen/kotlin Patch
@graphql-codegen/java-resolvers Patch
@graphql-codegen/c-sharp-common Patch
@graphql-codegen/c-sharp-operations Patch
@graphql-codegen/c-sharp Patch
@graphql-codegen/typescript-apollo-angular Patch
@graphql-codegen/typescript-apollo-client-helpers Patch
@graphql-codegen/typescript-document-nodes Patch
@graphql-codegen/typescript-generic-sdk Patch
@graphql-codegen/gql-tag-operations Patch
@graphql-codegen/typescript-graphql-apollo Patch
@graphql-codegen/typescript-graphql-request Patch
@graphql-codegen/typescript-jit-sdk Patch
@graphql-codegen/typescript-mongodb Patch
@graphql-codegen/typescript-msw Patch
@graphql-codegen/typescript-oclif Patch
@graphql-codegen/typescript-operations Patch
@graphql-codegen/typescript-react-offix Patch
@graphql-codegen/typescript-react-apollo Patch
@graphql-codegen/typescript-react-query Patch
@graphql-codegen/typescript-resolvers Patch
@graphql-codegen/typescript-rtk-query Patch
@graphql-codegen/typescript-stencil-apollo Patch
@graphql-codegen/typescript-type-graphql Patch
@graphql-codegen/typed-document-node Patch
@graphql-codegen/typescript Patch
@graphql-codegen/typescript-urql-graphcache Patch
@graphql-codegen/urql-svelte-operations-store Patch
@graphql-codegen/typescript-urql Patch
@graphql-codegen/typescript-vue-apollo-smart-ops Patch
@graphql-codegen/typescript-vue-apollo Patch
@graphql-codegen/typescript-vue-urql Patch
@graphql-codegen/introspection Patch
@graphql-codegen/jsdoc Patch
@graphql-codegen/client-preset Patch
@graphql-codegen/gql-tag-operations-preset Patch
@graphql-codegen/graphql-modules-preset Patch
@graphql-codegen/import-types-preset Patch
@graphql-codegen/near-operation-file-preset Patch

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

@charlypoly
Copy link
Contributor

Hi @JanStevens,

Thank you for continuing @aradalvand's work here.
Please know that while adding a new option is a tempting solution, we aim to solve this issue #8296 at a higher level (as part of the v3 roadmap, by rewriting codegen's core).

Considering our existing plan to address the issues linked to the amount of generated code, we don't plan to add this feature to visitor-plugin-common.

Also, we don't judge this issue as blocking since:

  • we recommend not committing generated files (especially types)
  • we now provide a new preset (client-preset) that generates only types instead of hooks or SDKs, reducing the bundle's impact
  • as stated above, we plan to rewrite the core only to emit used types

@JanStevens
Copy link
Author

Hi @charlypoly,

Thanks for the swift answer, v3 sounds great! Concerning committing generated files: It's a bit hard to have a working typescript setup in various stages of CI / local development. Especially if those types are changing a lot, it could introduce typescript errors when performing production deploys so we rather have them committed.

Down the line I think that using the stripIgnoredCharacters is still an important feature to include as it greatly reduce the size of the generated.

I'll take a look at the client-preset

Regards

@aradalvand
Copy link
Contributor

aradalvand commented Oct 17, 2022

@charlypoly This is not about the types though, it's about the strings, strings aren't wiped out in the compliation step like types are (obviously) and so I don't see how your bullet points apply to this PR. Correct me if I'm wrong.

@JanStevens
Copy link
Author

@JanStevens This is not about the types though, it's about the strings, strings aren't wiped out in the compliation step like types are (obviously) and so I don't see how your bullet points apply to this PR. Correct me if I'm wrong.

My reply was not concerning this PR as it can be closed, but rather at the comment from @charlypoly regarding V3 ;)

@JanStevens JanStevens closed this Oct 17, 2022
@aradalvand
Copy link
Contributor

aradalvand commented Oct 17, 2022

My bad, I meant to mention @charlypoly... Made a mistake. I don't think this PR should've been closed! We need this option anyway.

@JanStevens
Copy link
Author

My bad, I meant to mention @charlypoly... Made a mistake. I don't think this PR should've been closed! We need this option anyway.

No worries, by all means reopen it 😉

@aradalvand
Copy link
Contributor

aradalvand commented Oct 17, 2022

No worries, by all means reopen it 😉

@JanStevens I can't, you're the author :)

I think you should keep it open unless @charlypoly decides otherwise. In this comment of mine I was trying to point out, in response to @charlypoly, that I'm not sure how his points were relevant to this particular feature, this PR/feature is concerned with the strings, and not the types; unless I've misunderstood something here.

@charlypoly Would love for you to clarify.

@JanStevens JanStevens reopened this Oct 18, 2022
@charlypoly
Copy link
Contributor

@charlypoly Would love for you to clarify.

Sure!
We now recommend using the client-preset for most GraphQL client (ex: front-end) use-cases because this new preset provides the smoothest developer experience and lightest code generator (for now, but will be improved in the future with a rewrite of the core of codegen).
While the client-preset still generates document nodes as follows:

const documents = {
    "\n  query allFilmsWithVariablesQuery($first: Int!) {\n    allFilms(first: $first) {\n      edges {\n        node {\n          ...FilmItem\n        }\n      }\n    }\n  }\n": types.AllFilmsWithVariablesQueryDocument,
    "\n  fragment FilmItem on Film {\n    id\n    title\n    releaseDate\n    producers\n  }\n": types.FilmItemFragmentDoc,
};

it heavily relies on TypeScript function overloads on the provided graphql() helper, meant to be used to replace graphql-tag:

const documents = {
    "\n  query allFilmsWithVariablesQuery($first: Int!) {\n    allFilms(first: $first) {\n      edges {\n        node {\n          ...FilmItem\n        }\n      }\n    }\n  }\n": types.AllFilmsWithVariablesQueryDocument,
    "\n  fragment FilmItem on Film {\n    id\n    title\n    releaseDate\n    producers\n  }\n": types.FilmItemFragmentDoc,
};

export function graphql(source: "\n  query allFilmsWithVariablesQuery($first: Int!) {\n    allFilms(first: $first) {\n      edges {\n        node {\n          ...FilmItem\n        }\n      }\n    }\n  }\n"): (typeof documents)["\n  query allFilmsWithVariablesQuery($first: Int!) {\n    allFilms(first: $first) {\n      edges {\n        node {\n          ...FilmItem\n        }\n      }\n    }\n  }\n"];
export function graphql(source: "\n  fragment FilmItem on Film {\n    id\n    title\n    releaseDate\n    producers\n  }\n"): (typeof documents)["\n  fragment FilmItem on Film {\n    id\n    title\n    releaseDate\n    producers\n  }\n"];

export function graphql(source: string): unknown;
export function graphql(source: string) {
  return (documents as any)[source] ?? {};
}

As you might guess, stripping all ignored characters will break the TS function overloading here.

While this PR still applies to existing plugins, we are right now focusing our efforts on bringing new features to the v3 roadmap and fixing blockers in existing versions.

@JanStevens
Copy link
Author

You could still use stripIgnoredCharacters in both documents and graphql to make it condenser 🤔

I'm looking forward for the new approach, right now I can't really grasp how to use this with for example graphql-request but I guess as v3 comes a long more documentation / migration will become clear

@charlypoly
Copy link
Contributor

You could still use stripIgnoredCharacters in both documents and graphql to make it condenser 🤔

Yes but then your GraphQL Operations would need to be written in a condensed way at the source too.

I'm looking forward for the new approach, right now I can't really grasp how to use this with for example graphql-request but I guess as v3 comes a long more documentation / migration will become clear

You will find a complete example here: https://github.com/dotansimha/graphql-code-generator/tree/master/examples/front-end/react/graphql-request and new documentation here: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue

@JanStevens
Copy link
Author

You will find a complete example here: https://github.com/dotansimha/graphql-code-generator/tree/master/examples/front-end/react/graphql-request and new documentation here: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue

Cool, thanks for the docs. We currently have a setup with .graphql files and fragments as .graphql files (ex: event.fragments.graphql). For larger projects this makes it easier to have reusable (and discoverable) fragments / queries. Would that be supported in v3? I don't necessarily see how that would work 🤔.

@aradalvand
Copy link
Contributor

aradalvand commented Oct 18, 2022

I can't wrap my head around this supposed v3 client-preset thing, the document constant there is an object whose keys are document strings, and whose values are... what?!
Makes no sense.

@charlypoly
Copy link
Contributor

Cool, thanks for the docs. We currently have a setup with .graphql files and fragments as .graphql files (ex: event.fragments.graphql). For larger projects this makes it easier to have reusable (and discoverable) fragments / queries. Would that be supported in v3? I don't necessarily see how that would work 🤔.

The client-preset only support inline graphql tag based definitions, using the exposed graphql() helper.

I can't wrap my head around this supposed v3 client-preset thing, the document constant there is an object whose keys are document strings, and whose values are... what?!
Makes no sense.

The documents is mapping string literals (your GraphQL definitions) to their typing equivalent (TypedDocumentNode types)

In short, we use the literal GraphQL definition strings to build function overloads on graphql() that will return the proper typing.

@JanStevens JanStevens closed this Jan 2, 2023
@aradalvand
Copy link
Contributor

aradalvand commented Apr 26, 2023

@charlypoly Hi, it seems like v3 has been released and this aspect of the library hasn't really changed, so I think this PR is still relevant.
@JanStevens Could you please consider reopening this?

@aradalvand
Copy link
Contributor

@charlypoly Could you please respond?

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.

None yet

3 participants