vuejs / apollo

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

Queries never run unless using <ApolloQuery> tags | this.$apollo.queries + this.$apollo.client are empty | unable to run basic queries from documentation #503

Open hi2u opened 5 years ago

hi2u commented 5 years ago

I'm not sure if I just don't understand the documentation, of if this is a bug (I've seen a few similar bug reports). But I've tried creating multiple new projects with various versions of vue/vue-apollo (both with and without nuxt 1 and 2) since earlier last year, and I can never (or rarely) seem to get the basic simple queries from docs to work, i.e.

If I use <ApolloQuery> tags - it works fine.

Note that I'm using TypeScript. As far I can tell from some example projects, get apollo() {... } is the right way to define the queries. However this method get apollo() is never executed automatically... from what I understand of the docs, these queries are executed as soon as you load the page?

My code:

<script lang="ts">
  import { Component, Vue } from 'vue-property-decorator'

  export default class List extends Vue {

    myQueryName='my default value';

    get apollo() {
      return {
        myQueryName: {
          query: require('../graphql/listMeta.graphql'),
          // prefetch: true <-- tried with and without this
        }
      }
    }

  }
</script>

<template>
  <div>

    <!-- THIS DOESN"T WORK ... -->
    queries are: {{this.$apollo.queries}} <!-- THIS JUST SHOWS AN EMPTY OBJECT: {} -->
    <hr>
    myQueryName value is: {{myQueryName}} <!-- THIS JUST SHOWS "my default value"  -->
    <hr>
    typeof client: {{typeof this.$apollo.client}}  <!-- undefined  -->

    <hr>
    <!--
    THIS DOES WORK...
    <ApolloQuery :query="this.apollo.myQueryName.query" >
      <template slot-scope="{ result: { loading, error, data } }"></template>
    </ApolloQuery>
    -->
  </div>
</template>

Seeing it works fine and sends the query when I uncomment the <ApolloQuery> tags - I'm making the assumption that my global config is correct, but maybe there's some missing piece that I need to add there in order for vue-apollo to read the queries from get apollo() {...} and have them available in this.$apollo.queries ?

Here's my main.ts

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import { createProvider } from './vue-apollo'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  apolloProvider: createProvider(),
  render: h => h(App)
}).$mount('#app')

Here's my vue-apollo.js

import Vue from 'vue'
import VueApollo from 'vue-apollo'
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client'

// Install the vue plugin
Vue.use(VueApollo)

// Name of the localStorage item
const AUTH_TOKEN = 'apollo-token'
const httpEndpoint = 'http://gql.example.com/graphql'; // actual URL changed for github issue (the real one works with <ApolloQuery> tags
export const filesRoot = process.env.VUE_APP_FILES_ROOT || httpEndpoint.substr(0, httpEndpoint.indexOf('/graphql'))
Vue.prototype.$filesRoot = filesRoot

// Config
const defaultOptions = {
  httpEndpoint: httpEndpoint,
  tokenName: AUTH_TOKEN,
  persisting: false,
  websocketsOnly: false,
  ssr: false,
}

// Call this in the Vue app file
export function createProvider (options = {}) {
  // Create apollo client
  const { apolloClient, wsClient } = createApolloClient({
    ...defaultOptions,
    ...options,
  })
  apolloClient.wsClient = wsClient

  // Create vue apollo provider
  const apolloProvider = new VueApollo({
    defaultClient: apolloClient,
    defaultOptions: {
      $query: {
        // fetchPolicy: 'cache-and-network',
      },
    },
    errorHandler (error) {
      // eslint-disable-next-line no-console
      console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
    },
  })

  return apolloProvider
}

For the new project I created that I'm trying to get it working on right now, I've done the most "mainstream/recommended" regular way of creating that project that I can find right now...

    "noImplicitAny": false,
    "allowJs": true,
    "strict": false,

If I look at Object.keys(this.$apollo) in the template, I can see that it does exist, and the expected object keys exist: [ "_apolloSubscriptions", "_watchers", "vm", "queries", "subscriptions", "client", "loadingKey", "error" ]

The biggest clues are that:

I guess client being empty is the biggest sign? But why do the <ApolloQuery> tags work in that case?

What am I missing? Is there something else I need to do to "init" this.$apollo.config and this.$apollo.queries and have the query executed?

hi2u commented 5 years ago

I'm getting some thumbs ups on my initial post above, so seems I'm not alone with these issues.

For anyone else coming here with similar issues, can you please post some details so we can help narrow this down?

@murillio4 @hhsl @edward-simpson @alukos

e.g:

  1. Are <ApolloQuery> tags working for you?
  2. Have a look in this.$apollo like I've shown above, which properties contain the expected stuff? And which are undefined?
  3. Are you using the object or class-based syntax in your Vue script code?
  4. Are you using TypeScript?
  5. Are you using plain client-side only Vue, or with a SSR framework like Nuxt or Quasar etc?
  6. Are you seeing these issues with multiple versions of vue-apollo (and/or other packages)?
  7. Does it work on some of your pages, but not others? If so, can you think of any differences between them?
  8. Are you seeing the issue in multiple projects?
  9. Any other factors related to your project set up in general, or any other clues you might have?
  10. Please paste any relevant code you have.
  11. vue + vue-apollo version numbers, you can use this command to get them:
npm list vue vue-apollo

I'm currently on:

hhsl commented 5 years ago

I was struggeling with the same problem for some time, but found the solution here: https://github.com/vuejs/vue-class-component#adding-custom-hooks

For example just put the following into a hooks.ts, followed by importing this new file in your main.ts:

import Component from 'vue-class-component'

// Register the router hooks with their names
Component.registerHooks([
    'apollo'
])

Afterwards I was finally able to use the apollo getter in my components.

When this is really helping you as well, i think updating the documentation of vue-apollo with a typescript section, that hints to the custom hooks section of vue-class-component, might help.

fvigotti commented 5 years ago

I want to say that I had the same problem, with the following setup :

nuxt-ts / vue 2.6.6 / "@nuxtjs/apollo": "^4.0.0-rc4" -> Vue-Apollo 3.0.0-beta.28

the solution of @hhsl worked, I've created a plugin with


import {Component} from "~/node_modules/nuxt-property-decorator";

export default () => {

  Component.registerHooks([
    'apollo'
  ])
}

then imported in : nuxt.config.ts

definitely we need a better typerscript documentation, I'm pretty new to vue but also I'm not js/ts expert and an "easy to run" configuration/ guide is really far away.. I find myself always lost not knowing if each problem that show up is a bug , a misconfiguration ( also because the ts interfaces of apollo-module which then load vue-apollo ) or an incompatiblity between all those layers and maybe even with the additional interface layer of typescript which isn't documented, I've had to setup a frankenstein of code found around in guides/ tutorial/other sources, to have nuxt + apollo working with typescript,

my 2cents are that typescript native in all those libraries would also help managing so many moving parts..

fvigotti commented 5 years ago

errata corrige: the plugin works only for ".vue" components added in "components" dir but doesn't work in ".vue" pages I have in "pages" directory, for those I have had to add

Component.registerHooks([
    'apollo'
  ])

in each page..

overpod commented 5 years ago

same mistake

kezhenxu94 commented 5 years ago

I was struggeling with the same problem for some time, but found the solution here: https://github.com/vuejs/vue-class-component#adding-custom-hooks

For example just put the following into a hooks.ts, followed by importing this new file in your main.ts:

import Component from 'vue-class-component'

// Register the router hooks with their names
Component.registerHooks([
    'apollo'
])

Afterwards I was finally able to use the apollo getter in my components.

When this is really helping you as well, i think updating the documentation of vue-apollo with a typescript section, that hints to the custom hooks section of vue-class-component, might help.

Help me so much!!! I had the same problem and struggled for a whole day long and gave up back to JS, today I've found this, really helps a lot, thanks