0

I'm using graphql-codegen to generate typescript types for my graphql queries in my sveltekit project. However, graphql-codegen doesn't seem to recognize queries in template literals in my svelte files.

The urql docs show an example using graphql codegen in svelte for this purpose:

// codegen.ts
const config: CodegenConfig = {
  schema: '<YOUR_GRAPHQL_API_URL>',
  documents: ['src/**/*.svelte'],
  ignoreNoDocuments: true, // for better experience with the watcher
  generates: {
    './src/gql/': {
      preset: 'client',
      plugins: [],
    },
  },
};

export default config;

They also show an example using react where queries in template literals are automatically typed, and claim that "the usage remains the same for Vue and Svelte bindings":

import React from 'react';
import { useQuery } from 'urql';

import './App.css';
import Film from './Film';
import { graphql } from '../src/gql';

const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          ...FilmItem
        }
      }
    }
  }
`);

function App() {
  // `data` is typed!
  const [{ data }] = useQuery({
    query: allFilmsWithVariablesQueryDocument,
    variables: { first: 10 },
  });
  return (
    <div className="App">
      {data && (
        <ul>
          {data.allFilms?.edges?.map(
            (e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />
          )}
        </ul>
      )}
    </div>
  );
}

export default App;

Here is my source code with an example GraphQL query template literal:

<!-- src/routes/+page.svelte -->
<script lang="ts">
    import { onMount } from 'svelte';

    import { queryStore, getContextClient, gql } from '@urql/svelte';
    import { getContext } from 'svelte';
    import { graphql } from '../gql';

    const client = getContextClient();

    console.log('Saying hello...');

    const helloQuery = graphql(/* GraphQL */ `
        query {
            hello
        }
    `);

    onMount(async () => {
        const res = await client.query(helloQuery, {}).toPromise();
        console.log('Said hello! response:', res.data);
    });
</script>

I tried removing ignoreNoDocuments from my codegen config, which caused codegen to fail citing that template literals in svelte components cannot be parsed without installing svelte2tsx. After installing svelte2tsx, codegen finishes successfully but doesn't recognize my queries.

Unfortunately I can't find any examples of anyone successfully typing template literal queries in svelte, but it seems to be possible. The alternative is to write my queries in separate graphql files and import the generated output into my svelte and ts files, but that seems like more boilerplate and a bit less intuitive to take advantage of urql caching and svelte bindings.

Is it possible to type GraphQL query template literals in svelte components with current tooling? Is it even worth it, or would you suggest a different tech stack?

minnow
  • 183
  • 8

1 Answers1

0

While I haven't found a solution to template literals, I think I found a much better alternative anyways.

I wasn't aware that graphql-codegen introduced TypedDocumentNodes in 2020 which allow you to generate and import typed ASTs from your graphql documents. This is already a decent solution, however you would have to run graphql-codegen each time you update your documents, then import your ASTs into your typeescript code from the generated files.

I think I found an even better solution. graphql-tag packages two utilities for parsing GraphQL into ASTs, including a webpack loader to preprocess queries. This would allow you to import pre-processed ASTs from graphql files directly, skipping the generation step when using graphql-codegen.

The graphql-tag docs mentions some alternatives to the standard webpack loader, including solutions for typescript, babel, react native, next js, and jest.

I also found vite-plugin-graphql, which is perfect for a sveltekit project already leveraging vite, although this hasn't seen an update since it was published 3 years ago. Instead I found @rollup/plugin-graphql which is an official plugin maintained by the rollup team. The vite docs also list @rollup/plugin-graphql as being compatible along with a usage guide.

minnow
  • 183
  • 8
  • Unfortunately for some reason graphql files are not being recognized as modules in my svelte project with the rollup plugin installed according to the compatibility guide. I will update when I find the solution, or if someone else can shed some light in the meantime please do – minnow Jun 23 '23 at 19:58
  • I guess I realized there is one caveat with the preprocess approach. Currently, graphql pre-processing plugins do not generate TypedDocumentNodes, so while you can directly import queries from graphql files you do not actually get typed results. So unfortunately I will have to stick with graphql-codegen for now. – minnow Jun 24 '23 at 08:59
  • Addressing my last comment, I found the package [rollup-plugin-typed-gql](https://www.npmjs.com/package/rollup-plugin-typed-gql) which actually does generate preprocessed TypedDocumentNodes. However, this package was only published 2 months ago with 1 active contributor so I am a bit hesitant to use it in production. Seems useful for prototyping and personal projects at least. – minnow Jun 24 '23 at 09:12