Initialize URQL for Svelte the async way (I need to split schema.json in a separate chunk)

700 Views Asked by At

I'm using Svelte and URQL.

I'm using the svelte example in your packages folder here except I'm creating a format: 'esm' in my rollup.config.js.

My Rollup is already code-splitting my final bundle in chunks when I use import('./Component.svelte') in my code.

What I'm having hard time doing is initializing urql asynchronously, like this:

import { initClient, dedupExchange, fetchExchange } from '@urql/svelte'
import { cacheExchange } from "@urql/exchange-graphcache";

const exchanges = [
  cacheExchange({
    resolvers: { /*... my resolvers*/ },
    schema // I need this async, something like: await import('./schema').then(result => result.default)
  }),
  fetchExchange
]

export function initURQL () {
  initClient({
    url: 'http://localhost/graphql',
    exchanges
  })
}

If I use something like:

export async function initURQL () {
  const schema = await import('./schema.json').default

  const exchanges = [
  cacheExchange({
    resolvers: {},
    schema
  }),
  fetchExchange
  ]
  initClient({
    url: 'http://localhost/graphql',
    exchanges
  })
}`

and call it from App.svelte with ;(async () => await initURQL())() it gives me error:

Uncaught (in promise) Error: Function called outside component initialization

How can I fix this?

1

There are 1 best solutions below

0
On

I'm not using URQL but I've run into this error as well.

Unfortunately, you can't call getContext or setContext (which is what initClient in urql/packages/svelte-urql/src/context.ts calls) asynchronously.

https://svelte.dev/docs#setContext:

Like lifecycle functions, this must be called during component initialisation.

https://github.com/timhall/svelte-apollo/issues/9#issuecomment-646184888 answers a very similar question and hopefully points to a suitable workaround for you:

this happens with getClient and setClient because it is a svelte context which is only available at component initialization (construction) and cannot be in an event handler. see: the answer for Svelte user registration issue with setting store value Most likely what is happening is that you're calling it in an async event su as an on:click, onMount, onDestroy when it is not available. The solution to this is to store your client as a store in the context as per https://svelte.dev/tutorial/context-api.

In general it should probably look something like:

setClient(writable(apolloClient));

let client
getClient().subscribe((_client) => client = _client);