vuejs / apollo

🚀 Apollo/GraphQL integration for VueJS
http://apollo.vuejs.org
MIT License
6.02k stars 522 forks source link

Nuxt 3 support #1277

Open productdevbook opened 2 years ago

gerbenvanlaar commented 2 years ago

Hi! It's been a while since there has been an update on this topic. Does anyone have any news on the support for Nuxt 3?

joshistoast commented 2 years ago

Currently using this with Nuxt 3 and works fine

berradakamal commented 2 years ago

joshwcorbett, can you share please how did you manage the configuration?

ryntab commented 2 years ago

Found a Nuxt3 Apollo module that works. https://github.com/newbeea/nuxt3-apollo-module

gustawdaniel commented 2 years ago

I have problem with this package. It sometimes works, but seems to be unstable if is used with other packages. Problem that I have:

TypeError: (0 , import_vue_demi5.getCurrentInstance) is not a function                                                           
    at useQueryImpl (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/app/server.mjs:363:55)                               
    at Object.useQuery (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/app/server.mjs:359:11)                            
    at setup (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/app/server.mjs:13387:74)                                    
    at _sfc_main$3.setup (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/app/server.mjs:14201:25)                        
    at callWithErrorHandling (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/handlers/renderer.mjs:2536:23)              
    at setupStatefulComponent (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/handlers/renderer.mjs:8182:30)             
    at setupComponent (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/handlers/renderer.mjs:8163:12)                     
    at renderComponentVNode (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/handlers/renderer.mjs:10510:17)              
    at Object.ssrRenderComponent (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/handlers/renderer.mjs:10946:12)         
    at _sfc_ssrRender$1 (file:///home/daniel/pro/xue/nuxt/.output/server/chunks/app/server.mjs:14220:32)                         
[Vue warn]: Component <Anonymous> is missing template or render function.

is possible to reproduce if I install pinia, that have different (newer) version of vue-demi. During development everything is ok, but when I build and serve project I see this error.

I am checking if this pr will fix it:

https://github.com/vuejs/apollo/pull/1373

GitarMan commented 2 years ago

I'm having the same issue as @gustawdaniel above right now ^

joshistoast commented 2 years ago

joshwcorbett, can you share please how did you manage the configuration?

For all that are still lost here:

plugins/apollo.ts

import {
  ApolloClient,
  InMemoryCache,
  createHttpLink,
} from '@apollo/client/core'
import {
  DefaultApolloClient,
  provideApolloClient,
} from '@vue/apollo-composable'
import type { NuxtApp } from '#app'
import { defineNuxtPlugin } from '#app'

export default defineNuxtPlugin((nuxtApp: NuxtApp) => {

  const httpLink = createHttpLink({
    uri: '', // your endpoint
    headers: {
      // your headers
    },
  })

  const cache = new InMemoryCache()

  let apolloClient: ApolloClient<any>

  if (process.server) {
    apolloClient = new ApolloClient({
      ssrMode: true,
      link: httpLink,
      cache,
    })
    nuxtApp.hook('app:rendered', () => {
      nuxtApp.payload.data.apollo = apolloClient.extract()
    })
  }
  else {
    apolloClient = new ApolloClient({
      link: httpLink,
      cache,
    })
  }

  provideApolloClient(apolloClient)
  nuxtApp.provide('apollo', { DefaultApolloClient, apolloClient })
})
SteveEdson commented 2 years ago

I'm still getting an error using the above plugin, and the following versions:

Error:

 ERROR  [unhandledRejection] (0 , import_vue_demi7.getCurrentInstance) is not a function                                                                                                                                            10:51:38

  at Object.useMutation (.nuxt/prerender/chunks/app/server.mjs:633:55)
  at setup (.nuxt/prerender/chunks/app/add.b72ebafb.mjs:35:83)
  at _sfc_main.setup (.nuxt/prerender/chunks/app/add.b72ebafb.mjs:199:23)
  at callWithErrorHandling (.nuxt/prerender/chunks/renderer.mjs:2654:23)
  at setupStatefulComponent (.nuxt/prerender/chunks/renderer.mjs:9548:30)
  at setupComponent (.nuxt/prerender/chunks/renderer.mjs:9503:12)
  at renderComponentVNode (.nuxt/prerender/chunks/renderer.mjs:12068:17)
  at renderVNode (.nuxt/prerender/chunks/renderer.mjs:12191:22)
  at renderVNode (.nuxt/prerender/chunks/renderer.mjs:12197:17)
  at renderComponentSubTree (.nuxt/prerender/chunks/renderer.mjs:12155:13)
marcoborsoi commented 2 years ago

Hi @joshwcorbett, thanks for your solution! It's working great in dev and when building the nuxt app, but I'm facing the exactly same error as @SteveEdson when running nuxt generate. I have tried with @vue/apollo-composable and @apollo/client in dependencies and later in devDependencies, but the error remains. I was wondering if you guys have found a solution. Thank you!

In my case, it's when using a query:

 ERROR  [unhandledRejection] (0 , import_vue_demi5.getCurrentInstance) is not a function                   10:42:24

  at useQueryImpl (.nuxt/prerender/chunks/app/server.mjs:350:55)
  at Object.useQuery (.nuxt/prerender/chunks/app/server.mjs:346:11)
  at useGetGamesQuery (.nuxt/prerender/chunks/app/server.mjs:4658:15)
  at setup (.nuxt/prerender/chunks/app/index.f9f5d731.mjs:26:5)
  at _sfc_main.setup (.nuxt/prerender/chunks/app/index.f9f5d731.mjs:36:23)
  at callWithErrorHandling (.nuxt/prerender/chunks/renderer.mjs:2654:23)
  at setupStatefulComponent (.nuxt/prerender/chunks/renderer.mjs:9548:30)
  at setupComponent (.nuxt/prerender/chunks/renderer.mjs:9503:12)
  at renderComponentVNode (.nuxt/prerender/chunks/renderer.mjs:12068:17)
  at renderVNode (.nuxt/prerender/chunks/renderer.mjs:12191:22)

The error seems to come from here: https://github.com/vuejs/apollo/blob/v4/packages/vue-apollo-composable/src/useQuery.ts#L145

Ex-Zy commented 2 years ago

It help me for project with Nuxt3/Apollo/Typescipt Add to your nuxt.config.ts

build: { transpile: ["@apollo/client/core", "@vue/apollo-composable" ]},

fmarcheski commented 2 years ago

I'm unsure if others had the same issue as I had...but I was able to get Apollo/Nuxt3 working in Production. It appears to be an issue with Vite when building for Production, not specifically an issue with Apollo.

I had to define a "DEV" variable for Vite in my nuxt.config.js...and 'voila.

Hope this helps someone.

import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  vite: {
    define: {
      __DEV__: (process.env.NODE_ENV === "development").toString(),
    },
  },
});
joshistoast commented 2 years ago

My one gripe with my setup above is that simply using it within a component or page results in a client-side query versus server-side.

When using apollo client directly, no problems with ssr at all. Perhaps there's another issue or discussion related to this 🤷‍♂️

I've seen some move their queries to a composable which seems to work, but I feel like that shouldn't need to be necessary.

Der-Alex commented 2 years ago

Did anyone get server side rendering with qraphql to work and has a minimal example? I have configured my client like in @joshwcorbett example and have a simple <div v-if="!loading && !error"> ... </div> where I want to render data from graphql. But a curl localhost:3000 won't give me any data. It seems like the client config with ssrMode: true doesn't work with Nuxt 3 at the moment. I also tried to use https://github.com/newbeea/nuxt3-apollo-module but it still won't render anything server-side...

Der-Alex commented 2 years ago

If anyone wants to know how to get ssr to work:

  1. Don't use graphql queries inside a nuxt 3 middleware. This doesn't work at the moment (rc.8).
  2. You need to add @vue/apollo-ssr: ^4.0.0-alpha.18 to your packages.

After these changes ssr works fine.

joshistoast commented 2 years ago

@Der-Alex Are there any further modifications that should be made to the configuration with this dependency installed?

gillesgw commented 1 year ago

@joshwcorbett I managed to get SSR working while transferring cache to client that way :

In plugins/apollo.server.js:

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client/core'
import { DefaultApolloClient, provideApolloClient } from '@vue/apollo-composable'
import { getStates } from '@vue/apollo-ssr'
import { defineNuxtPlugin } from '#app'

import type { NuxtApp } from '#app'

export default defineNuxtPlugin((nuxtApp: NuxtApp) => {
  const config = useRuntimeConfig()
  const httpLink = createHttpLink({ uri: config.graphqlApiEndpoint, headers: {} })
  const cache = new InMemoryCache()
  let apolloClient: ApolloClient<any>
  apolloClient = new ApolloClient({ ssrMode: true, link: httpLink, cache })
  nuxtApp.hook('app:rendered', () => {
    nuxtApp.payload.data.apollo = getStates({ apolloClient })
  })

  provideApolloClient(apolloClient)
  nuxtApp.provide('apollo', { DefaultApolloClient, apolloClient })
})

In plugins/apollo.client.js:

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client/core'
import { DefaultApolloClient, provideApolloClient } from '@vue/apollo-composable'
import { defineNuxtPlugin } from '#app'

import type { NuxtApp } from '#app'

export default defineNuxtPlugin((nuxtApp: NuxtApp) => {
  const config = useRuntimeConfig()
  const httpLink = createHttpLink({ uri: config.graphqlApiEndpoint, headers: {} })
  let apolloClient: ApolloClient<any>
  const cache = new InMemoryCache()
  cache.restore(window.__NUXT__.data.apollo.apolloClient)
  apolloClient = new ApolloClient({ link: httpLink, cache })
  provideApolloClient(apolloClient)
  nuxtApp.provide('apollo', { DefaultApolloClient, apolloClient })
})

I don't know why but I didn't manage to do it in only one global plugin with process.server helper, code was running on client anyway. Also, even if everything seems to work, I have a Hydration children mismatch warning in console but I'm not sure if this is ralated.

Der-Alex commented 1 year ago

A few days have passed and the https://apollo.nuxtjs.org/ module has been upgraded to version 5-alpha.3. This works well except for useQuery. For now I would recommend to use @nuxtjs/apollo@next with nuxt 3 and use useAsyncQuery which works fine.

productdevbook commented 1 year ago
[nuxt] [request error] [unhandled] [500] Named export 'DefaultApolloClient' not found. The requested module '@vue/apollo-composable' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@vue/apollo-composable';
const { provideApolloClient, DefaultApolloClient } = pkg;
productdevbook commented 1 year ago

Hello everyone, since I am developing a project on apollo and graphql, I decided to write this structure completely. Because updates are coming late. Also a project, this structure is the main structure. The better it is, the better we can make money.

For now, I have shared some developments with you. You can take a look if you're interested.

https://twitter.com/productdevbook/status/1605962566185799685

I hope to share more updates on both vue 3 and nuxt 3 in the coming days. You can stay tuned. Besides, these follows will be an excuse for me to move forward on this project.

productdevbook commented 1 year ago

I published it. https://twitter.com/productdevbook/status/1606198773583171584

productdevbook commented 1 year ago

https://github.com/huntersofbook/huntersofbook/issues/161

I changed some parts of useQuery and improved it.

I need tests, who can test on their project and give feedback

keithmifsud commented 1 year ago

A few days have passed and the https://apollo.nuxtjs.org/ module has been upgraded to version 5-alpha.3. This works well except for useQuery. For now I would recommend to use @nuxtjs/apollo@next with nuxt 3 and use useAsyncQuery which works fine.

The cache doesn't work though. Every query is network-only.

keithmifsud commented 1 year ago

huntersofbook/huntersofbook#161

I changed some parts of useQuery and improved it.

I need tests, who can test on their project and give feedback

Hi @productdevbook ... thanks a lot for sharing your work :smile: ... I've tried your plugin but unfortunately it doesn't prerender the data server side. It only runs the queries on the client side. Did I miss something missing from the playground example or this is expected?

Der-Alex commented 1 year ago

The cache doesn't work though. Every query is network-only.

  1. npm i -D @apollo/client @nuxtjs/apollo@next @vue/apollo-composable --legacy-peer-deps Important: --legacy-peer-deps because one of the pakages wants to install an older version of vuejs. This can cause trouble sometimes.
  2. Add apollo config to nuxt.config.ts
    apollo: {
    clients: {
      default: {
        httpEndpoint: 'INSERT YOUR ENDPOINT HERE'
      },
    },
    },
  3. Create plugins/apollo.js|ts
    import { provideApolloClient } from '@vue/apollo-composable';
    export default defineNuxtPlugin((nuxtApp) => {
    provideApolloClient(useApollo().clients.default);
    });
  4. Now you should be able to use all the graphql magic
    
    <script setup>
    import { YOUR_QUERY } from 'YOUR_PATH';
    const your_variables = { /* whatever */ };
    const your_config = { fetchPolicy: 'cache-first' };

const foo = await useAsyncQuery(YOUR_QUERY, your_variables); const bar = await useQuery(CMS_GET_NODE_BY_PATH, your_variables, your_config);

console.log(foo.data?.value); console.log(bar.result?.value);

keithmifsud commented 1 year ago

The cache doesn't work though. Every query is network-only.

  1. npm i -D @apollo/client @nuxtjs/apollo@next @vue/apollo-composable --legacy-peer-deps Important: --legacy-peer-deps because one of the pakages wants to install an older version of vuejs. This can cause trouble sometimes.
  2. Add apollo config to nuxt.config.ts
apollo: {
    clients: {
      default: {
        httpEndpoint: 'INSERT YOUR ENDPOINT HERE'
      },
    },
  },
  1. Create plugins/apollo.js|ts
import { provideApolloClient } from '@vue/apollo-composable';
export default defineNuxtPlugin((nuxtApp) => {
  provideApolloClient(useApollo().clients.default);
});
  1. Now you should be able to use all the graphql magic
<script setup>
import { YOUR_QUERY } from 'YOUR_PATH';
const your_variables = { /* whatever */ };
const your_config = { fetchPolicy: 'cache-first' };

const foo = await useAsyncQuery(YOUR_QUERY, your_variables);
const bar = await useQuery(CMS_GET_NODE_BY_PATH, your_variables, your_config);

console.log(foo.data?.value);
console.log(bar.result?.value);
</script>

Thank you @Der-Alex ...unfortunately, I also need SSR through Nuxt

DmitriVyaznikov commented 1 year ago

How to get smth like 'loading' from useAsyncQuery in @nuxtjs/apollo@next? 'pending' is not enough

keithmifsud commented 1 year ago

How to get smth like 'loading' from useAsyncQuery in @nuxtjs/apollo@next? 'pending' is not enough

I think useAsyncQuery is best for SSR https://apollo.nuxtjs.org/getting-started/composables#usequery Thus there's no need for loading.

On the client side, this will work:

const { result: myQueryResult, loading: loadingMyQuery } = await useQuery(MY_QUERY);
DmitriVyaznikov commented 1 year ago
await useQuery

but I find this info https://github.com/vuejs/apollo/issues/1219#issuecomment-981130424

so my target is to get loading status while I'm using nuxt/apollo (ssr: true)

keithmifsud commented 1 year ago
await useQuery

but I find this info #1219 (comment)

so my target is to get loading status while I'm using nuxt/apollo (ssr: true)

The comment is probably right :smile: What useQuery does is it prefetches on the server so that the sever returns the populated HTML, but then it fetches again on the client side so that you can show a loader.

If you try it and test it on bulld, you'll see the first Network response with populated HTMLa dn then a subsequent response for the GQL query.

I cannot see why you'd want a loader on the server, no one will see it.