apollo
apollo copied to clipboard
Example usage with Vue Composition API
What problem does this feature solve?
Vue-Apollo 4.x.x alpha release is based on the new Vue Composition API. Would be great to be able to use it with @nuxtjs/apollo
I will take a look at that.
Any progress on this? Tried the apollo module with the new useQuery
and get a Error: Apollo Client with id default not found
By the way, is there a workaround to use @nuxtjs/apollo
in a nuxt project which uses composition API with @vue/composition-api
?
I found an option how to use @vue/apollo-composable
. Need to perform a couple of simple steps:
Install @vue/apollo-composable
, create plugin provide-apollo-client.ts
(name can be any) with the following content:
// plugins/provide-apollo-client.js
import { provide } from '@vue/composition-api';
import { DefaultApolloClient } from '@vue/apollo-composable';
export default ({ app }) => {
app.setup = () => {
const apolloClient = app.apolloProvider.defaultClient;
provide(DefaultApolloClient, apolloClient);
}
}
Specify it in the config with the main API
// nuxt.config.js
plugins: [
'@/plugins/composition-api',
'@/plugins/provide-apollo-client'
],
The rest of the configuration is no different. However, there are still unsolved problems with SSR errors (example: 404 status code).
@negezor I think assigning app.setup = () => { ... }
could be a problem if more than one Nuxt plugin want to customize app.setup
... i.e. this is not composable in itself and raises a TS error Type '() => void' is not assignable to type 'SetupFunction<Data, Data>'.
Maybe injecting apolloClient the usual "nuxt way" could work ... I also asked a related question on Discord.
This points to a missing feature of Nuxt for making plugins work nicely with the Composition API.
Following @negezor's plugin, (@lewebsimple and in a more nuxy way via nuxt-composition-api):
// ~/plugins/apollo/provide.ts
import { provide, reactive } from "nuxt-composition-api";
import { Context, Plugin } from "@nuxt/types";
import { ApolloClients } from "@vue/apollo-composable";
const provideApollo: Plugin = ({ app }: Context) => {
app.setup = () => {
// since plugin is eval'd after module app.apolloProvider will always be defined
const clients = reactive(app.apolloProvider?.clients);
provide(DefaultApolloClient, clients?.defaultClient);
// not functionally important but req'd return type
return { [ApolloClients]: clients };
};
};
export default provideApollo;
One important thing to note is that @vue/apollo-composable
expects a config named default
, whereas @nuxtjs/apollo
's default config is named defaultClient
. If you provide ApolloClients
vs. DefaultApolloClient
, you must use { clientId: "defaultConfig" }
as an option when calling apollo-composeable
.
<template>
{{ result.company.name }}
</template>
<script lang="ts">
import { Component, Vue } from "nuxt-property-decorator";
import "vue-apollo"; // just noticed this is here, don't recall why...
import { useCompanyQuery } from "@/generated/graphql-codegen";
@Component({
setup: () => {
const { result, loading, error } = useCompanyQuery({
where: { isParent: true }
});
return { result, loading, error };
}
})
export default class CompaniesCard extends Vue {}
</script>
NB: Companies and Company are different queries.
~For fluency's sake defaultClient
needs to be renamed default
for interop. with @vue/apollo-composable
.~
Edit: Weirdly enough vue-apollo does use defaultClient
, and @vue/apollo-composeable
uses a different property name.
Hi,
I'm pretty sure I made a mistake somewhere ... I have this error displayed:
const useFetch = (callback) => {
var _a;
const vm = getCurrentInstance();
if (!vm)
throw new Error('This must be called within a setup function.');
registerCallback(vm, callback);
if (typeof vm.$options.fetchOnServer === 'function') {
vm._fetchOnServer = vm.$options.fetchOnServer.call(vm) !== false;
}
nuxt.config.js
buildModules: [
'@nuxt/typescript-build',
'nuxt-composition-api',
],
modules: [
'@nuxtjs/apollo',
],
plugins: [
'~/plugins/provideApolloClient.ts',
],
apollo: {
...
./plugins/provideApolloClient.ts
import { provide, reactive } from 'nuxt-composition-api';
import { Context, Plugin } from '@nuxt/types';
import { DefaultApolloClient } from '@vue/apollo-composable';
const provideApollo: Plugin = ({ app }: Context) => {
app.setup = () => {
// since plugin is eval'd after module app.apolloProvider will always be defined
const clients = reactive(app.apolloProvider?.clients);
provide(DefaultApolloClient, clients?.defaultClient);
// not functionally important but req'd return type
return { [DefaultApolloClient]: clients };
};
};
export default provideApollo;
index.vue
import 'vue-apollo'; // just noticed this is here, don't recall why...
package.json
"dependencies": {
"@nuxt/types": "^2.13.3",
"@vue/apollo-composable": "^4.0.0-alpha.8",
"graphql-tag": "^2.10.4",
"nuxt-composition-api": "^0.10.6",
},
"devDependencies": {
"@nuxtjs/apollo": "^4.0.1-rc.1",
The complet projext: https://github.com/shenron/vue-nuxt-tsx
Has someone a clue? Thank you very much.
Edit: Now I don't have errors, just a the page is in pending. The same query works with @nuxt/apollo without composition.
Edit 2: The last version of nuxt-composition-api
works with this is: "nuxt-composition-api": "^0.8.2"
There's an update to nuxt-composition-api
that provides an onGlobalSetup
hook. So now the plugin can just be
(typescript)
import { Context } from "@nuxt/types";
import { provide, onGlobalSetup, defineNuxtPlugin } from "nuxtjs/composition-api";
import { DefaultApolloClient } from "@vue/apollo-composable";
/**
* This plugin will connect @nuxt/apollojs with @vue/apollo-composable
*/
export default defineNuxtPlugin({ app }: Context): void => {
onGlobalSetup(() => {
provide(DefaultApolloClient, app.apolloProvider?.defaultClient);
});
});
and then of course add the plugin
plugins: ["@/plugins/apollo/plugin.ts"]
edit: use @nuxtjs/composition-api and defineNuxtPlugin
Just a note from @NickBolles response (which worked perfect for me), the nuxt composition api library is now @nuxtjs/composition-api'
so it should be:
import { provide, onGlobalSetup } from '@nuxtjs/composition-api'
Thanks @toddheslin! I've updated the example above to use the new @nuxtjs/composition-api and the defineNuxtPlugin
helper too.
Fixed up example
import { Context } from '@nuxt/types';
import { provide, onGlobalSetup, defineNuxtPlugin } from "@nuxtjs/composition-api";
import { DefaultApolloClient } from "@vue/apollo-composable";
/**
* This plugin will connect @nuxt/apollojs with @vue/apollo-composable
*/
export default defineNuxtPlugin(({ app }: Context): void => {
onGlobalSetup(() => {
provide(DefaultApolloClient, app.apolloProvider?.defaultClient);
});
})
Fixed up example
import { Context } from '@nuxt/types'; import { provide, onGlobalSetup, defineNuxtPlugin } from "@nuxtjs/composition-api"; import { DefaultApolloClient } from "@vue/apollo-composable"; /** * This plugin will connect @nuxt/apollojs with @vue/apollo-composable */ export default defineNuxtPlugin(({ app }: Context): void => { onGlobalSetup(() => { provide(DefaultApolloClient, app.apolloProvider?.defaultClient); }); })
My project has an error, please tell me how to solve this problem
Cannot read property 'DefaultApolloClient' of undefined
nuxt - 2.15.3 @nuxtjs/apollo - 4.0.1-rc.5 @nuxtjs/composition-api - 0.22.1 @vue/apollo-composable - 4.0.0-alpha.12
Console error ERROR [Vue warn]: Error in data(): "TypeError: Cannot read property 'DefaultApolloClient' of undefined"
@Rasool-deldar try @nuxtjs/composition-api - @0.21.0
@Rasool-deldar try @nuxtjs/composition-api - @0.21.0
install @nuxtjs/composition-api - 0.21.0 & 0.20.0
It still shows this error - Cannot read property 'DefaultApolloClient' of undefined
link test ( display error ) - https://codesandbox.io/s/elastic-satoshi-otjer
@Rasool-deldar That link wasn't working but here is what I'm currently using:
"@nuxtjs/apollo": "^4.0.1-rc.5",
"@nuxtjs/composition-api": "^0.21.0",
"@vue/apollo-composable": "^4.0.0-alpha.12"
Now I remember what I had to change to get it to this point...
- transpile in
nuxt.config.js
/*
** Build configuration
*/
build: {
transpile: ['@vue/apollo-composable'],
},
Then, replace all references to import like this (from /dist):
import { DefaultApolloClient } from '@vue/apollo-composable/dist'
That's what I needed to do to move from an earlier version (I've been using it for about a year) till the latest ones)
Hope this helps!
dist
import { DefaultApolloClient } from '@vue/apollo-composable/dist'
Thank you for your help.
I have used this method
import { DefaultApolloClient } from '@vue/apollo-composable'
I have replaced it with the following method
import { DefaultApolloClient } from '@vue/apollo-composable/dist'
I tested it on this version, it worked 0.21.0 & 0.22.3 @nuxtjs/apollo": "^4.0.1-rc.5", "@nuxtjs/composition-api": "^0.21.0", "@vue/apollo-composable": "^4.0.0-alpha.12"
@Rasool-deldar That link wasn't working but here is what I'm currently using:
"@nuxtjs/apollo": "^4.0.1-rc.5", "@nuxtjs/composition-api": "^0.21.0", "@vue/apollo-composable": "^4.0.0-alpha.12"
Now I remember what I had to change to get it to this point...
- transpile in
nuxt.config.js
/* ** Build configuration */ build: { transpile: ['@vue/apollo-composable'], },
Then, replace all references to import like this (from /dist):
import { DefaultApolloClient } from '@vue/apollo-composable/dist'
That's what I needed to do to move from an earlier version (I've been using it for about a year) till the latest ones)
Hope this helps!
how use ssr ? .
not work ssr useQuery( Test, {}, { prefetch: true, } );
https://codesandbox.io/s/falling-glitter-t4ko2?file=/pages/index.vue:848-938
SSR should just work out of the box. When the page is loaded from the server, the GQL request is made server-side, otherwise it's client.
Not sure what issue you're facing here but glad to know the config changes got the upgrade to work 👍
SSR should just work out of the box. When the page is loaded from the server, the GQL request is made server-side, otherwise it's client.
Not sure what issue you're facing here but glad to know the config changes got the upgrade to work 👍
I do not know exactly how to handle ssr. Without waiting for the data to go to the server, it goes to the data client, and there it says, please help me, how can I solve this problem? ( localhost - npm run dev )
Look at this link below in the terminal and console, you will see the undefined value on the server side, then the data value will return to the user side.
nuxt-mode ssr: true,
https://codesandbox.io/s/falling-glitter-t4ko2?file=/pages/index.vue:848-938
OK I see your problem here. You can't use async functions in a vue 2.x setup function (ie current version of nuxt). I'll add some commentary:
const movies = ref([]);
// No point doing async/await here because the callback function is called after data is resolved
onResult(async ({ data }) => {
movies.value = await data.movies;
});
// this will always be undefined because we aren't blocking the component from rendering above (and can't)
console.log(result.value);
// same as above
console.log(movies.value);
// setup() is called on both server and client, so it's a bit misleading to log 'ssr' here
console.log("ssr");
The correct way to do it is this:
<script>
import { defineComponent } from "@nuxtjs/composition-api";
import { useQuery, useResult } from "@vue/apollo-composable/dist";
export default defineComponent({
components: {
Logo,
IconLink,
},
setup() {
// not work ssr
const { result, loading, error } = useQuery(
Test,
{},
{
fetchPolicy: "no-cache",
prefetch: true,
}
);
const movies = useResult(result)
return {
movies,
error,
loading,
};
},
});
</script>
In your <template>
you can render out movies
if we aren't loading
or if there is no error
. The only time you need to really use onResult()
(which I do use a lot) is where you are setting module-scoped refs from a composable that need to be shared state between different components. This is more of an advanced case when you're feeling comfortable with the above.
Check out useResult
here: https://v4.apollo.vuejs.org/guide-composable/query.html#useresult
SSR should just work out of the box. When the page is loaded from the server, the GQL request is made server-side, otherwise it's client. Not sure what issue you're facing here but glad to know the config changes got the upgrade to work 👍
I do not know exactly how to handle ssr. Without waiting for the data to go to the server, it goes to the data client, and there it says, please help me, how can I solve this problem? ( localhost - npm run dev )
Look at this link below in the terminal and console, you will see the undefined value on the server side, then the data value will return to the user side.
nuxt-mode ssr: true,
https://codesandbox.io/s/falling-glitter-t4ko2?file=/pages/index.vue:848-938 Thank you very much for your help
OK I see your problem here. You can't use async functions in a vue 2.x setup function (ie current version of nuxt). I'll add some commentary:
const movies = ref([]); // No point doing async/await here because the callback function is called after data is resolved onResult(async ({ data }) => { movies.value = await data.movies; }); // this will always be undefined because we aren't blocking the component from rendering above (and can't) console.log(result.value); // same as above console.log(movies.value); // setup() is called on both server and client, so it's a bit misleading to log 'ssr' here console.log("ssr");
The correct way to do it is this:
<script> import { defineComponent } from "@nuxtjs/composition-api"; import { useQuery, useResult } from "@vue/apollo-composable/dist"; export default defineComponent({ components: { Logo, IconLink, }, setup() { // not work ssr const { result, loading, error } = useQuery( Test, {}, { fetchPolicy: "no-cache", prefetch: true, } ); const movies = useResult(result) return { movies, error, loading, }; }, }); </script>
In your
<template>
you can render outmovies
if we aren'tloading
or if there is noerror
. The only time you need to really useonResult()
(which I do use a lot) is where you are setting module-scoped refs from a composable that need to be shared state between different components. This is more of an advanced case when you're feeling comfortable with the above.Check out
useResult
here: https://v4.apollo.vuejs.org/guide-composable/query.html#useresult
Thank you very much for your help. 👍 👍 👍
Anybody experienced the error of TypeError: defaultClientConfig is undefined
here is my plugin:
import {Context} from '@nuxt/types'
import {
provide,
onGlobalSetup,
defineNuxtPlugin
} from '@nuxtjs/composition-api'
import {DefaultApolloClient} from '@vue/apollo-composable/dist'
/**
* This plugin will connect @nuxt/apollojs with @vue/apollo-composable
*/
export default defineNuxtPlugin(({app}: Context): void => {
onGlobalSetup(() => {
provide(DefaultApolloClient, app.apolloProvider?.defaultClient)
})
})
I also added the transpile configuration on my nuxt.config.js
build: {
...
transpile: ['@vue/apollo-composable']
},
I have tried setting it up as described by others in this issue. However, I am currently having trouble with the Nuxt client throwing the following error: "Apollo client with id default not found. Use provideApolloClient() if you are outside of a component setup."
Initially it renders the page correctly with the GraphQL query being executed correctly on the server, but it seems to fail after it gets hydrated. Here is a repository to reproduce the issue: https://github.com/Tomaszal/nuxt-apollo-composable-test
After some debugging, it seems that ~~this resolveClient function is being called with an undefined value~~ injecting ApolloClients and DefaultApolloClient returns null on the Nuxt client, but I cannot figure out why. Perhaps someone knows better why this is happening?
EDIT: Was a silly mistake. I copied the code for the plugin with DefaultApolloClient being imported from '@vue/apollo-composable', but I imported the composition functions from '@vue/apollo-composable/dist' instead. If anyone has the same issue make sure to import everything from the same place, as DefaultApolloClient is a unique symbol. Not sure if the '/dist' part is still necessary, for me it works without it.
I have tried setting it up as described by others in this issue. However, I am currently having trouble with the Nuxt client throwing the following error: "Apollo client with id default not found. Use provideApolloClient() if you are outside of a component setup."
Initially it renders the page correctly with the GraphQL query being executed correctly on the server, but it seems to fail after it gets hydrated. Here is a repository to reproduce the issue: https://github.com/Tomaszal/nuxt-apollo-composable-test
After some debugging, it seems that ~this resolveClient function is being called with an undefined value~ injecting ApolloClients and DefaultApolloClient returns null on the Nuxt client, but I cannot figure out why. Perhaps someone knows better why this is happening?
EDIT: Was a silly mistake. I copied the code for the plugin with DefaultApolloClient being imported from '@vue/apollo-composable', but I imported the composition functions from '@vue/apollo-composable/dist' instead. If anyone has the same issue make sure to import everything from the same place, as DefaultApolloClient is a unique symbol. Not sure if the '/dist' part is still necessary, for me it works without it.
import { Context } from '@nuxt/types'
import {
onGlobalSetup,
defineNuxtPlugin
} from '@nuxtjs/composition-api'
// @ts-ignore
import { provideApolloClient } from '@vue/apollo-composable'
/**
* This plugin will connect @nuxt/apollojs with @vue/apollo-composable
*/
export default defineNuxtPlugin(({ app }: Context): void => {
onGlobalSetup(() => {
provideApolloClient(app.apolloProvider?.defaultClient)
})
})
With Nuxt 2 Bridge this is how I defined the provider, see: https://stackoverflow.com/q/73986807/2771889
import { provideApolloClient } from '@vue/apollo-composable'
export default defineNuxtPlugin((nuxtApp) => {
provideApolloClient(nuxtApp.apolloProvider?.defaultClient)
})