Typesafety on GraphQL query template literals in Svelte?

227 Views Asked by At

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?

1

There are 1 best solutions below

3
minnow On

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.