I have started having an issue with apollo client in vue2 when using inside a watch.
I have followed the setup guide for apollo client when using the composition api:
https://v4.apollo.vuejs.org/guide-composable/setup.html#_2-connect-apollo-client-to-vue
so my main.ts looks like this:
import contentfulClient from "./plugins/vue-apollo-contentful";
import apiClient from "./plugins/vue-apollo-api";
Vue.config.productionTip = false;
Vue.use(VueApollo);
new Vue({
router,
store,
vuetify,
setup() {
provide(ApolloClients, {
default: apiClient,
apiClient,
contentfulClient,
});
},
render: (h) => h(App),
}).$mount("#app");
The clients have their own files and are setup the same:
import { ApolloClient } from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
const uri = `https://graphql.contentful.com/content/v1/spaces/${process.env.VUE_APP_CONTENTFUL_SPACE_ID}/environments/${process.env.VUE_APP_CONTENTFUL_ENV}?access_token=${process.env.VUE_APP_CONTENTFUL_ACCESS_TOKEN}`;
const link = createHttpLink({
uri,
});
const cache = new InMemoryCache();
const contentfulClient = new ApolloClient({
link,
cache,
});
export default contentfulClient;
I have this component:
import { defineComponent, onMounted, ref, watch } from "#vue/composition-api";
import { useGetCategory } from "#/logic/get-category";
export default defineComponent({
name: "Categories",
setup(_, context) {
const slug = ref(context.root.$route.params.slug);
const result = ref({});
const getCategory = (slug) => {
console.log(slug);
const { category, loading, error } = useGetCategory(slug);
result.value = { category, loading, error };
};
watch(() => context.root.$route.params.slug, getCategory);
onMounted(() => getCategory(slug.value));
return { result };
},
});
When this component loads, it "gets the category" by executing this:
import { useQuery, useResult } from "#vue/apollo-composable";
import * as getCategoryBySlug from "#/graphql/api/query.category.gql";
export function useGetCategory(slug: string) {
const { result, loading, error } = useQuery(getCategoryBySlug, { slug });
const category = useResult(result, null, (data) => data.getCategoryBySlug);
return { category, loading, error };
}
When the page loads, it gets the category fine, but if I change the route parameter (slug) I expect it to get the new category and display it. But instead I get this error:
So I figured that the setup is wrong in main.ts, so I added the non-composition-api aswell, found here:
https://apollo.vuejs.org/guide/installation.html#_1-apollo-client
Now my main.ts looks like this:
import contentfulClient from "./plugins/vue-apollo-contentful";
import apiClient from "./plugins/vue-apollo-api";
Vue.config.productionTip = false;
const apolloProvider = new VueApollo({
defaultClient: apiClient,
});
Vue.use(apolloProvider);
new Vue({
router,
store,
vuetify,
apolloProvider,
setup() {
provide(ApolloClients, {
default: apiClient,
apiClient,
contentfulClient,
});
},
render: (h) => h(App),
}).$mount("#app");
But this does not work. It compiles, but I still get the same error.
Does anyone know what I need to do to get this to work?
What works for me is
setup() {
provide(DefaultApolloClient, apolloClient);
},
Related
I've build my app with Vite. I read many documents on web about the topic but I'm still very confused. I've a login form that send credentials to a protected view. When post the data I set the headers and store the Bearer token in the local storage.
The problem is that it doesn't work cause the Bearer token result equal to null.
Only when I logout the token is set in the headers.
That's how is the header when I log in
And here how it's set when I log out...
My main.js code is this:
import { createApp, provide, h } from "vue";
import {
ApolloClient,
createHttpLink,
InMemoryCache,
} from "#apollo/client/core";
import { DefaultApolloClient } from "#vue/apollo-composable";
import App from "./App.vue";
import router from "./router";
import { createPinia } from "pinia";
import { provideApolloClient } from "#vue/apollo-composable";
const authToken = localStorage.getItem("auth-token");
const httpLink = createHttpLink({
uri: "http://localhost/graphql",
headers: {
Authorization: "Bearer " + authToken,
},
});
const cache = new InMemoryCache();
const apolloClient = new ApolloClient({
link: httpLink,
cache,
});
provideApolloClient(apolloClient);
const app = createApp({
setup() {
provide(DefaultApolloClient, apolloClient);
},
render: () => h(App),
});
app
.use(router)
.use(createPinia())
.mount("#app");
and this is my routes.js
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
const isAuthenticated = localStorage.getItem('auth-token');
if(requiresAuth && isAuthenticated===null){
next('/auth/login');
}else {
next();
}
});
I'm surely making some mistakes in my main.js but I cannot understand what's wrong. I'm very confused :-/
Thanks to who'll be able to help me.
Try using a helper function to get the token from local storage; I'm using this method and it's working fine for me. To get your code more organized, create a separate folder to define the apollo client. Here is the code:
// apolloClient.ts
import { ApolloClient, InMemoryCache, HttpLink } from "#apollo/client/core";
function getHeaders() {
const headers: { Authorization?: string; "Content-Type"?: string } = {};
const token = localStorage.getItem("access-token");
if (token) {
headers["Authorization"] = `Bearer ${token}`;
}
headers["Content-Type"] = "application/json";
return headers;
}
// Create an http link:
const httpLink = new HttpLink({
uri: `${import.meta.env.VITE_API_URL}/graphql`,
fetch: (uri: RequestInfo, options: RequestInit) => {
options.headers = getHeaders();
return fetch(uri, options);
},
});
// Create the apollo client
export const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: httpLink,
defaultOptions: {
query: {
errorPolicy: "all",
},
mutate: {
errorPolicy: "all",
},
},
});
Then you can use it in your main.ts like this:
// main.ts
import { createApp, h } from "vue";
import { provideApolloClient } from "#vue/apollo-composable";
import App from "./App.vue";
import { apolloClient } from "./apolloClient";
const app = createApp({
setup() {
provideApolloClient(apolloClient);
},
render: () => h(App),
});
app.mount("#app");
I can't access my routes from the store.
There may be a good explanation for this.
I use Vuejs3 and Pinia
My store :
import {defineStore} from 'pinia'
import {useRoute} from "vue-router";
type navigationState = {
selectedNavigationItem: INavigationItem | null,
selectedNavigationPage: INavigationPage | null,
}
export const useNavigationStore = defineStore('navigationStore', {
state: () => ({
/**
* when the user clicks on an element of the navbar we store the navigation item here
*/
selectedNavigationItem: null,
/**
* when the user clicks on an element of the sidebar we store the navigation page here
*/
selectedNavigationPage: null,
} as navigationState),
actions: {
/**
* Set Selected navigation page
* #param navigationPage
* #type INavigationPage
*/
setSelectedNavigationPage(navigationPage: INavigationPage | null) {
console.log(useRoute())
this.selectedNavigationPage = navigationPage
},
},
})
when I do a console log like in the method setSelectedNavigationPage
I have an undefined
useRoute and useRouter must be used in Vue components and specifically setup method or inside script setup.
useRouter Docs
useRoute Docs
If you want to access the router though, you can simply import it:
router-file
import { createRouter, createWebHistory } from 'vue-router'
export const router = createRouter({
history: createWebHistory(),
routes: [/* ... */]
})
then in your pinia store you can import and use the router from that file:
import { defineStore } from 'pinia'
import router from './router'
export const myStore = defineStore('myStore', () => {
// router.push
// router.replace
})
EDIT: Thanks for sophiews for pointing this out.
Just found out that we have different way to defineStore: Setup Stores
// src/stores/user.js
import { defineStore } from 'pinia'
import { useRoute, useRouter } from 'vue-router'
import api from './api.js'
export const useUserStore = defineStore('User', () => { // use function
const route = useRoute()
const router = useRouter()
const login = async () => {
await api.POST('login', {username, password})
router.replace({name: 'home'})
}
return { login } // IMPORTANT: need to return anything we need to expose
})
Old answer
You can add router as Pinia plugin
// src/main.js
import { createPinia } from 'pinia'
import { createApp, markRaw } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Home from './views/HomePage.vue'
import Api from './api.js' // my axios wrapper
const app = createApp(App)
// I usually put this in a separate file src/router.js and export the router
const routes = [
{ path: '/', component: HomePage },
]
const router = createRouter({
history: createWebHistory(),
routes,
})
const pinia = createPinia()
pinia.use(({ store }) => {
store.router = markRaw(router)
store.api = markRaw(Api)
})
app
.use(pinia)
.use(router)
.mount('#app')
Then router and api are available on this
// src/stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('User', {
state: () => ({}),
actions: {
async login() {
await this.api.POST('login', {username, password})
this.router.replace({name: 'home'})
}
}
})
Note that you can't call this.router with arrow function.
login: async () => {
this.router.replace({name: 'home'}) // error
}
For typescript user, to correctly get type for this.router and this.api:
// src/global.d.ts
import { Router } from 'vue-router'
import Api from './api'
export { }
declare global {
}
declare module 'pinia' {
export interface PiniaCustomProperties {
router: Router,
api: typeof Api
}
}
I found this way on pinia github.
https://github.com/vuejs/pinia/discussions/1092
But I still don't know how to add this.route to Pinia.
Future reader, please comment if you know how to do it.
You could wrap the process of instantiating a store within a factory/function, this will allow you to expand the stores capabilities regarding your custom needs. Below you can see that we can instantiate a store referencing the urql client and the router object.
Have a look:
export class StoreManager {
static _instances: any[] = [];
public static spawnInstance(
id: string,
storeType?: EStoreType,
clientHandle?: ClientHandle,
routerHandle?: Router,
) {
if (StoreManager._instances.find((i) => i.id === id)) {
const store = StoreManager._instances.find((i) => i.id === id).instance;
return store;
} else {
const store = StoreManager.initStore(
id,
storeType,
clientHandle ?? null,
routerHandle ?? null,
);
StoreManager._instances.push({
id: id,
instance: store,
storeType: storeType,
});
return store;
}
}
public static initStore(
id: string,
storeType: EStoreType,
clientHandle: ClientHandle | null,
routerHandle: Router | null,
) {
const baseState = {
_meta: {
storeType: storeType,
isLoading: true,
},
_client: clientHandle,
_router: routerHandle,
};
const baseActions = {
async query(query: any, variables: any[] = []) {
// use urql client
},
};
const baseGetters = {
storeType: (state) => state._meta.storeType,
getCurrentRoute: (state) => {
if (!state._router) {
throw new RouterNotSetException(
`This store does not have a router set up`,
);
}
return state._router.currentRoute.fullPath.replace('/', '');
},
};
switch (storeType) {
case EStoreType.DEFAULT:
return defineStore({
id: `${id}`,
state: () => ({
...baseState,
}),
actions: {
...baseActions,
},
getters: {
...baseGetters,
},
});
default:
throw new StoreTypeNotFoundException(
`Expected valid 'EStoreType', got ${storeType}`,
);
}
}
}
Within your VueComponent a store instance would be spawned like this:
const store = StoreManager.spawnInstance(
uuidv4(),
EStoreType.DEFAULT,
useClientHandle(),
useRouter(),
)();
I have created a Vue3 application using the Vue CLI to create my application with Vuex and Router. The application runs well.
Note: I followed this useful doc for the Vuex with Vue3 https://blog.logrocket.com/using-vuex-4-with-vue-3/
Requirement Now I would like to change my Vue3 application to have Server Side Rendering support(i.e. SSR).
I watched this awesome video on creating an SSR application using Vue3 : https://www.youtube.com/watch?v=XJfaAkvLXyU and I can create and run a simple application like in the video. However I am stuck when trying to apply it to my main Vue3 app.
My current sticking point is how to specify the router and vuex on the server code.
My Code
The client entry file (src/main.js) has the following
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
createApp(App).use(store).use(router).mount('#app');
The server entry file (src/main.server.js) currently has the following
import App from './App.vue';
export default App;
And in the express server file (src/server.js) it currently has
const path = require('path');
const express = require('express');
const { createSSRApp } = require('vue');
const { renderToString } = require('#vue/server-renderer');
...
...
server.get('*', async (req, res) => {
const app = createSSRApp(App);
const appContent = await renderToString(app);
I need to change this code so that the app on the server side is using the router and vuex like it is on the client.
Issues
In the express server file i can not import the router and vuex like in the client entry file as it fails due to importing outside a module, therefore in the express server I can not do the following
const app = createSSRApp(App).use(store).use(router);
I have tried changing the server entry file (src/main.server.js) to the following, but this does not work either.
import App from './App.vue';
import router from './router';
import store from './store';
const { createSSRApp } = require('vue');
export default createSSRApp(App).use(store).use(router);
Does anyone know how to do SSR in Vue 3 when your app is using Vuex and Router.
How i did this in Vue 2 is below and what i am trying to change over to Vue 3
My Vue2 version of this application had the following code
src/app.js creates the Vue component with the router and store specified
Client entry file (src/client/main.js) gets the app from app.js, prepopulates the Vuex store with the data serialized out in the html, mounts the app when the router is ready
import Vue from 'vue';
import { sync } from 'vuex-router-sync';
import App from './pages/App.vue';
import createStore from './vuex/store';
import createRouter from './pages/router';
export default function createApp() {
const store = createStore();
const router = createRouter();
sync(store, router);
const app = new Vue({
router,
store,
render: (h) => h(App),
});
return { app, router, store };
}
Server Entry file (src/server/main.js), gets the app from app.js, get the matched routes which will call the "serverPrefetch" on each component to get its data populated in the Vuex store, then returns the resolve promise
import createApp from '../app';
export default (context) => new Promise((resolve, reject) => {
const { app, router, store } = createApp();
router.push(context.url);
router.onReady(() => {
const matchedComponents = router.getMatchedComponents();
if (!matchedComponents.length) {
return reject(new Error('404'));
}
context.rendered = () => {
context.state = store.state;
};
return resolve(app);
}, reject);
});
Express server (/server.js) uses the bundle renderer to render the app to a string to put in the html
const fs = require('fs');
const express = require('express');
const { createBundleRenderer } = require('vue-server-renderer');
const dotenv = require('dotenv');
dotenv.config();
const bundleRenderer = createBundleRenderer(
require('./dist/vue-ssr-server-bundle.json'),
{
template: fs.readFileSync('./index.html', 'utf-8'),
},
);
const server = express();
server.use(express.static('public'));
server.get('*', (req, res) => {
const context = {
url: req.url,
clientBundle: `client-bundle.js`,
};
bundleRenderer.renderToString(context, (err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found');
} else {
res.status(500).end('Internal Server Error');
}
} else {
res.end(html);
}
});
});
const port = process.env.PORT || 3000
server.listen(port, () => {
console.log(`Listening on port ${port}`);
});
I have managed to find the solution to this thanks to the following resources:
Server Side Rendering with Vue.js 3 video: https://www.youtube.com/watch?v=XJfaAkvLXyU&feature=youtu.be and git repos: https://github.com/moduslabs/vue3-example-ssr
SSR + Vuex + Router app : https://github.com/shenron/vue3-example-ssr
migrating from Vue 2 to Vue 3
https://v3-migration.vuejs.org/breaking-changes/introduction.html
migrating from VueRouter 3 to VueRouter 4
https://next.router.vuejs.org/guide/migration/
migrating from Vuex 3 to Vuex 4
https://next.vuex.vuejs.org/guide/migrating-to-4-0-from-3-x.html
client entry file (src/main.js)
import buildApp from './app';
const { app, router, store } = buildApp();
const storeInitialState = window.INITIAL_DATA;
if (storeInitialState) {
store.replaceState(storeInitialState);
}
router.isReady()
.then(() => {
app.mount('#app', true);
});
server entry file (src/main-server.js)
import buildApp from './app';
export default (url) => new Promise((resolve, reject) => {
const { router, app, store } = buildApp();
// set server-side router's location
router.push(url);
router.isReady()
.then(() => {
const matchedComponents = router.currentRoute.value.matched;
// no matched routes, reject with 404
if (!matchedComponents.length) {
return reject(new Error('404'));
}
// the Promise should resolve to the app instance so it can be rendered
return resolve({ app, router, store });
}).catch(() => reject);
});
src/app.js
import { createSSRApp, createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
const isSSR = typeof window === 'undefined';
export default function buildApp() {
const app = (isSSR ? createSSRApp(App) : createApp(App));
app.use(router);
app.use(store);
return { app, router, store };
}
server.js
const serialize = require('serialize-javascript');
const path = require('path');
const express = require('express');
const fs = require('fs');
const { renderToString } = require('#vue/server-renderer');
const manifest = require('./dist/server/ssr-manifest.json');
// Create the express app.
const server = express();
// we do not know the name of app.js as when its built it has a hash name
// the manifest file contains the mapping of "app.js" to the hash file which was created
// therefore get the value from the manifest file thats located in the "dist" directory
// and use it to get the Vue App
const appPath = path.join(__dirname, './dist', 'server', manifest['app.js']);
const createApp = require(appPath).default;
const clientDistPath = './dist/client';
server.use('/img', express.static(path.join(__dirname, clientDistPath, 'img')));
server.use('/js', express.static(path.join(__dirname, clientDistPath, 'js')));
server.use('/css', express.static(path.join(__dirname, clientDistPath, 'css')));
server.use('/favicon.ico', express.static(path.join(__dirname, clientDistPath, 'favicon.ico')));
// handle all routes in our application
server.get('*', async (req, res) => {
const { app, store } = await createApp(req);
let appContent = await renderToString(app);
const renderState = `
<script>
window.INITIAL_DATA = ${serialize(store.state)}
</script>`;
fs.readFile(path.join(__dirname, clientDistPath, 'index.html'), (err, html) => {
if (err) {
throw err;
}
appContent = `<div id="app">${appContent}</div>`;
html = html.toString().replace('<div id="app"></div>', `${renderState}${appContent}`);
res.setHeader('Content-Type', 'text/html');
res.send(html);
});
});
const port = process.env.PORT || 8080;
server.listen(port, () => {
console.log(`You can navigate to http://localhost:${port}`);
});
vue.config.js
used to specify the webpack build things
const ManifestPlugin = require('webpack-manifest-plugin');
const nodeExternals = require('webpack-node-externals');
module.exports = {
devServer: {
overlay: {
warnings: false,
errors: false,
},
},
chainWebpack: (webpackConfig) => {
webpackConfig.module.rule('vue').uses.delete('cache-loader');
webpackConfig.module.rule('js').uses.delete('cache-loader');
webpackConfig.module.rule('ts').uses.delete('cache-loader');
webpackConfig.module.rule('tsx').uses.delete('cache-loader');
if (!process.env.SSR) {
// This is required for repl.it to play nicely with the Dev Server
webpackConfig.devServer.disableHostCheck(true);
webpackConfig.entry('app').clear().add('./src/main.js');
return;
}
webpackConfig.entry('app').clear().add('./src/main-server.js');
webpackConfig.target('node');
webpackConfig.output.libraryTarget('commonjs2');
webpackConfig.plugin('manifest').use(new ManifestPlugin({ fileName: 'ssr-manifest.json' }));
webpackConfig.externals(nodeExternals({ allowlist: /\.(css|vue)$/ }));
webpackConfig.optimization.splitChunks(false).minimize(false);
webpackConfig.plugins.delete('hmr');
webpackConfig.plugins.delete('preload');
webpackConfig.plugins.delete('prefetch');
webpackConfig.plugins.delete('progress');
webpackConfig.plugins.delete('friendly-errors');
// console.log(webpackConfig.toConfig())
},
};
src/router/index.js
import { createRouter, createMemoryHistory, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const isServer = typeof window === 'undefined';
const history = isServer ? createMemoryHistory() : createWebHistory();
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
component: About,
},
];
const router = createRouter({
history,
routes,
});
export default router;
src/store/index.js
import Vuex from 'vuex';
import fetchAllBeers from '../data/data';
export default Vuex.createStore({
state() {
return {
homePageData: [],
};
},
actions: {
fetchHomePageData({ commit }) {
return fetchAllBeers()
.then((data) => {
commit('setHomePageData', data.beers);
});
},
},
mutations: {
setHomePageData(state, data) {
state.homePageData = data;
},
},
});
Github sample code
I found I needed to go through the building the code step by step doing just SSR, just Router, just Vuex and then put it all together.
My test apps are in github
https://github.com/se22as/vue-3-with-router-basic-sample
"master" branch : just a vue 3 app with a router
"added-ssr" branch : took the "master" branch and added ssr code
"add-just-vuex" branch : took the "master" branch and added vuex code
"added-vuex-to-ssr" branch : app with router, vuex and ssr.
You can also use Vite which has native SSR support and, unlike Webpack, works out-of-the-box without configuration.
And if you use vite-plugin-ssr then it's even easier.
The following highlights the main parts of vite-plugin-ssr's Vuex example
<template>
<h1>To-do List</h1>
<ul>
<li v-for="item in todoList" :key="item.id">{{item.text}}</li>
</ul>
</template>
<script>
export default {
serverPrefetch() {
return this.$store.dispatch('fetchTodoList');
},
computed: {
todoList () {
return this.$store.state.todoList
}
},
}
</script>
import Vuex from 'vuex'
export { createStore }
function createStore() {
const store = Vuex.createStore({
state() {
return {
todoList: []
}
},
actions: {
fetchTodoList({ commit }) {
const todoList = [
{
id: 0,
text: 'Buy milk'
},
{
id: 1,
text: 'Buy chocolate'
}
]
return commit('setTodoList', todoList)
}
},
mutations: {
setTodoList(state, todoList) {
state.todoList = todoList
}
}
})
return store
}
import { createSSRApp, h } from 'vue'
import { createStore } from './store'
export { createApp }
function createApp({ Page }) {
const app = createSSRApp({
render: () => h(Page)
})
const store = createStore()
app.use(store)
return { app, store }
}
import { renderToString } from '#vue/server-renderer'
import { html } from 'vite-plugin-ssr'
import { createApp } from './app'
export { render }
export { addContextProps }
export { setPageProps }
async function render({ contextProps }) {
const { appHtml } = contextProps
return html`<!DOCTYPE html>
<html>
<body>
<div id="app">${html.dangerouslySetHtml(appHtml)}</div>
</body>
</html>`
}
async function addContextProps({ Page }) {
const { app, store } = createApp({ Page })
const appHtml = await renderToString(app)
const INITIAL_STATE = store.state
return {
INITIAL_STATE,
appHtml
}
}
function setPageProps({ contextProps }) {
const { INITIAL_STATE } = contextProps
return { INITIAL_STATE }
}
import { getPage } from 'vite-plugin-ssr/client'
import { createApp } from './app'
hydrate()
async function hydrate() {
const { Page, pageProps } = await getPage()
const { app, store } = createApp({ Page })
store.replaceState(pageProps.INITIAL_STATE)
app.mount('#app')
}
Simplest example: Updated with the latest document on the Vue website.
https://github.com/ThinhVu/vue--just-ssr
You can find more examples in this repository which included more about impl SSR in the real world.
The repository not only includes naive implement in VueJs but also contains an example using Vite only, Vite + Vite-SSR-plugin, Nuxt, QuasarJS
(I'm working on it, more examples will be added later).
https://github.com/ThinhVu/vue-ssr-labs
Is it possible to use garbage collection cache.gc() with vue-apollo?
Is there any way to clean all store cache data?
For example, is it possible to run it inside a lifecycle?
<script>
import { apolloClient } from "#/main";
export default {
mounted() {
this.$apollo.cache.gc();
// or may be this.$apollo.queries.birds.cache.gc();
// or this.$store.cache.gc();
},
};
</script>
I can not get a list after the first register. I have to refresh it.
first, init apollo client:
import { ApolloClients } from '#vue/apollo-composable';
import { createApp, provide, h } from 'vue';
import App from './App.vue';
// other ...
const apolloClient = new ApolloClient({
link: from([errorLink, requestInterceptor, authLink, traceLink, httpLink]),
cache: new InMemoryCache({
addTypename: false
})
});
const app = createApp({
setup() {
provide(ApolloClients, {
default: apolloClient
});
},
render: () => h(App)
});
export default apolloClient
then, you can clear apollo network cache whenever you want:
import apolloClient from 'xxx.ts'
apolloClient.cache.reset()
How to make apollo accessible outside vue component.
I am verifying if the user exist and then allow the route to proceed further.
{
path: '/:username',
name: 'userProfilePage',
component: userProfilePage,
beforeEnter(routeTo, routeFrom, next) {
userExist(routeTo.params.username)
next()
}
Passing the username as a parameter to the userExist function.
import gql from "graphql-tag"
export default function userExist(username) {
this.$apollo
.query({
query: gql`
query($username: String!) {
login(username: $username) {
username
email
}
}
`,
variables: {
username: username
}
})
.then(res => {
console.log(res);
return res
})
.catch(err => {
console.log(err);
return err
});
}
But it is outputting the error:
Apollo client code
import Vue from 'vue'
import App from './App.vue'
import VueApollo from 'vue-apollo';
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import router from './routes.js'
Vue.config.productionTip = false
const httpLink = new HttpLink({
uri: process.env.VUE_APP_DB_URL,
})
const cache = new InMemoryCache()
const apolloClient = new ApolloClient({
link: httpLink,
cache
})
Vue.use(VueApollo)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
new Vue({
render: h => h(App),
router,
apolloProvider
}).$mount('#app')
So instead of initializing the apollo client in the App.vue file, initialize it in another file.
Something like clients.js, and export that client:
const httpLink = new HttpLink({
uri: process.env.VUE_APP_DB_URL,
})
const cache = new InMemoryCache()
export const apolloClient = new ApolloClient({
link: httpLink,
cache
})
Once done, import that in App.vue file like this:
import { apolloClient } from './clients.js';
Vue.use(VueApollo)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
new Vue({
render: h => h(App),
router,
apolloProvider
}).$mount('#app')
Once done, import that client in any other file you want:
import { apolloClient } from './client.js';
import gql from "graphql-tag"
export default function userExist(username) {
apolloClient
.query({
query: gql`
query($username: String!) {
login(username: $username) {
username
email
}
}
`,
variables: {
username: username
}
})
.then(res => {
console.log(res);
return res
})
.catch(err => {
console.log(err);
return err
});
}