nuxt-modules / apollo

Nuxt.js module to use Vue-Apollo. The Apollo integration for GraphQL.
https://apollo.nuxtjs.org
MIT License
929 stars 194 forks source link

Multiple calls to `useAsyncQuery` from composable function causes 500 error in SSR #614

Open pixleight opened 2 months ago

pixleight commented 2 months ago

Environment


Describe the bug

Calling useAsyncQuery more than once inside a composable function results in a 500 error when loading a SSR route, with the following error message:

[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at `https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables`.

Expected behaviour

Should be able to execute more than a single query in a composable function.

Reproduction

https://stackblitz.com/edit/github-tfy4rs?file=composables%2FuseMultipleQuery.ts

Example composable function:

export const useMultipleQuery = async () => {
  const dataOne = ref();
  const dataTwo = ref();

  const responseOne = await useAsyncQuery(gql`
    query Launches {
      launches {
        id
        mission_name
      }
    }
  `);
  dataOne.value = responseOne.data.value;

  const responseTwo = await useAsyncQuery(gql`
    query Rockets {
      rockets {
        id
        description
      }
    }
  `);
  dataTwo.value = responseTwo.data.value;

  return {
    dataOne,
    dataTwo,
  };
};

Additional context

Executing multiple queries with useAsyncQuery works as expected when inside <script setup> or loading a route in client-side context.

Logs

500

[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at `https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables`.

at useApollo (./node_modules/@nuxtjs/apollo/dist/runtime/composables.mjs:75:41)
at prep (./node_modules/@nuxtjs/apollo/dist/runtime/composables.mjs:26:23)
at Module.useAsyncQuery (./node_modules/@nuxtjs/apollo/dist/runtime/composables.mjs:16:32)
at Module.useMultipleQuery (./composables/useMultipleQuery.ts:19:51)
at async setup (./app.js:19:12)
filiphazardous commented 2 months ago

I also ran into this. I solved it by wrapping things in useNuxtApp().runWithContext(async () => { /* my code here */ })

I think this is more like a limitation of Nuxt, perhaps? After awaiting an async call, it's like I have been transported out of the usual Nuxt context and into a then-function of a Promise. So context probably has to be re-established.

ronaldevers commented 1 month ago

Relevant Nuxt documentation:

The context is unset by Nuxt/Vue after the first await leading to the error on the second.

I think you can either use runWithContext as suggested by @filiphazardous or for for example multiple await $fetch() calls, I've wrapped them in an async handler function that I use with useAsyncData(handler, ...).