d4rekanguok/gatsby-typescript

Allow codegen for non-gatsby schemas

Closed this issue ยท 7 comments

I apologize if this issue is specific however I don't know where else to post about it.

It's sort of an issue with graphql-codegen but also specific to codegen in a gatsby context via this plugin so I'll start here ๐Ÿ˜…

Please let me know if I missed something!

The issue

Using the @apollo/client (v3.0.0-beta.32), requires you import the gql tag from apollo like so:

import { useQuery, gql } from '@apollo/client';

// ๐Ÿ”ด gatsby-plugin-graphql-codegen will try to create types using the wrong schema
const myQuery = gql`
  // ...
`;

The issue is, when I do this, graphql-codegen will try to create types for this query using the Gatsby schema. This is an issue because the Apollo client I have set up should point to a different graphql schema than the schema created via gatsby during build time.

The workaround

I have a temporary workaround of importing gql via require like so:

// โœ… gatsby-plugin-graphql-codegen will ignore this
const { gql: apolloGql } = require('@apollo/client');

const myQuery = apolloGql`
  // ...
`;

Recommendations

At the minimum, it would be nice if it were possible to add some sort of way to ignore codegen for particular patterns (e.g. importing from @apollo/client). This way this plugin stays focused on just doing codegen for gatsby related queries.

Going all in, we could work towards this plugin officially supporting the Apollo client via allowing an additional non-gatsby schema and generating a different types file per the type of graphql tag. I'm not too sure how to get this working or even it makes sense but hopefully this will inspire.

Thanks for any help!

Hi @ricokahler, thanks for coming back with another interesting issue (I still owe you a response in #29!)

Going all in, we could work towards this plugin officially supporting the Apollo client via allowing an additional non-gatsby schema and generating a different types file per the type of graphql tag

I really like that!

However it looks like graphql-toolkit (the lib that scan code files for graphql documents) doesn't expose an api for filter/ignore graphql tags, and the returned graphql documents also don't contain information of their graphql tags & libraries. We'd need to open an issue at graphql-toolkit & see if the folks there want to support this.

With the current setup, we can only filter documents by theirs file paths and operation type :/ which doesn't seem too helpful.

That makes sense. I had a feeling I'd have to open another upstream lol

That's good info though. Looking at the repo, it seems like graphql-tag-pluck is the package we need this feature in. I'll propose it and we'll see what happens.

I was doing a bit of digging in that repo and it seems like they do actually expose an API for picking the particular tags. ๐Ÿ‘‡

export interface GraphQLTagPluckOptions {
  modules?: Array<{ name: string; identifier?: string }>;
  gqlMagicComment?: string;
  globalGqlIdentifierName?: string | string[];
}

And we can override this config via options to loadDocuments. This options object eventually gets passed to the CodeFileLoader options


So it seems it is actually possible to codegen for different schemas based on the tag type ๐ŸŽ‰

Here is a very rough idea of how I'm thinking we could implement this.

1. override the default GraphQLTagPluckOptions['modules'] configuration to only pluck types for Gatsby related files.

This means instead of using the default modules value, we go with this ๐Ÿ‘‡

const pluckConfig = {
  modules: [
    { name: 'gatsby', identifier: 'graphql', },
    globalGqlIdentifierName: 'graphql', // <-- this is for `gatsby-node` `.ts` files from my other issue
  ],
};

Why?

If we limit the scope of modules graphql-tag-pluck will try to codegen for, we'll ensure we're not using the Gatsby schema for Apollo Client queries or similar.

2. add a new configuration to this plugin e.g. additionalSchemas (or similar) that allows the user to specify a pluckConfig, a schema, and a corresponding types output file.

So if I was adding support for the Apollo Client, my gatsby-config could look something along the lines of this:

const getSchemaSomehow = () => /* ... */;

module.exports = {
  // ...
  plugins: [
    // ...
    {
      resolve: 'gatsby-plugin-graphql-codegen',
      options: {
        // ...
        additionalSchemas: [
          {
            pluckConfig: {
              modules: [{ name: '@apollo/client', identifier: 'gql' }],
              globalGqlIdentifierName: [],
            },
            filename: 'apollo-types.ts',
            schema: getSchemaSomehow(),
          },
        ],
      },
    },
  ],
};

This probably needs more thought but something like this could work.

Let me know what you think!

Wow, great work! For whatever reasons, when I saw that module option earlier, I asumed that setting it would add more tags instead of overwriting the defaults. Thanks for that!

It's definitely possible to get this feature out then. I think the config you propose makes sense. Maybe add an option to declare more file paths as well.

I think the steps could be:

  • limit plucking to Gatsby's tag only

  • add loadSchema support

  • refactor the gataby-node portion to be able to run codegen for multiple configs

  • expose new config options

And then I'll need to start adding tests as well ๐Ÿ˜…

Let me know what you think and if you'd have time to help with these!

Yeah I have some time. I can probably get a PR to you within the next few days if you'll take it. I can also set up jest for the repo in a separate PR if you want too.

Thanks @ricokahler, I'll take them all โ€” please send PRs!

If you know a typescript + gatsby + apollo opensource projects / starter that we can test this plugin with, please share as well.

@devuxer @kokokenada @imanbee thanks for leaving a like on the parent issue. Just want to let you know this feature is now supported in v2.6.0, thanks to @kije!