apollo
apollo copied to clipboard
Empty SSR page content when `pollInterval` is set
Version
Reproduction link
https://github.com/chriscalo/nuxt-apollo-polling
Steps to reproduce
- Create Nuxt app (
yarn create nuxt-app nuxt-apollo-polling
) - Add
@nuxtjs/apollo
and create basic graphql server - Add graphql query to a
.vue
page and include apollInterval
(See the exact steps I've taken in the repro repo commits)
For example, in pages/index.vue
:
<script>
import Logo from '~/components/Logo.vue'
import { User } from '~/queries/auth.graphql'
export default {
apollo: {
user: {
query: User,
prefetch: true,
// adding this `pollInterval` value causes the problem
pollInterval: 1000,
},
},
components: {
Logo
}
}
</script>
What is expected ?
Adding a pollInterval
to an Apollo query works without breaking anything.
What is actually happening?
Adding a pollInterval
value causes the server to return empty page content. You can see this by right-clicking the page and selecting View Page Source
. All of the Nuxt <scripts>
and containing <div>
s are there, but the page content is empty.
Here's what I see in the <body>
when the pollInterval
is present:
<div data-server-rendered="true" id="__nuxt"><!----><div id="__layout"><div><script>window.__NUXT__={layout:"default",data:[{}],error:null,serverRendered:true,apollo:{defaultClient:Object.create(null)},logs:[]};</script><script src="/_nuxt/runtime.js" defer></script><script src="/_nuxt/pages/index.js" defer></script><script src="/_nuxt/pages/index.a474644729814055f4ea.hot-update.js" defer></script><script src="/_nuxt/commons.app.js" defer></script><script src="/_nuxt/vendors.app.js" defer></script><script src="/_nuxt/app.js" defer></script>
Compare that with what's in the <body>
when the pollInterval
is removed:
<div data-server-rendered="true" id="__nuxt"><!----><div id="__layout"><div><div class="container"><div><svg width="245" height="180" viewBox="0 0 452 342" xmlns="http://www.w3.org/2000/svg" class="NuxtLogo"><g fill="none" fill-rule="evenodd"><path d="M139 330l-1-2c-2-4-2-8-1-13H29L189 31l67 121 22-16-67-121c-1-2-9-14-22-14-6 0-15 2-22 15L5 303c-1 3-8 16-2 27 4 6 10 12 24 12h136c-14 0-21-6-24-12z" fill="#00C58E"></path> <path d="M447 304L317 70c-2-2-9-15-22-15-6 0-15 3-22 15l-17 28v54l39-67 129 230h-49a23 23 0 0 1-2 14l-1 1c-6 11-21 12-23 12h76c3 0 17-1 24-12 3-5 5-14-2-26z" fill="#108775"></path> <path d="M376 330v-1l1-2c1-4 2-8 1-12l-4-12-102-178-15-27h-1l-15 27-102 178-4 12a24 24 0 0 0 2 15c4 6 10 12 24 12h190c3 0 18-1 25-12zM256 152l93 163H163l93-163z" fill="#2F495E" fill-rule="nonzero"></path></g></svg> <h1 class="title">
nuxt-apollo-polling
</h1> <h2 class="subtitle">
repro for polling bug in @nuxtjs/apollo
</h2> <p>
user = [email protected]
</p> <div class="links"><a href="https://nuxtjs.org/" target="_blank" class="button--green">
Documentation
</a> <a href="https://github.com/nuxt/nuxt.js" target="_blank" class="button--grey">
GitHub
</a></div></div></div></div></div></div><script>window.__NUXT__={layout:"default",data:[{}],error:null,serverRendered:true,apollo:{defaultClient:Object.create(null,{ROOT_QUERY:{writable:true,enumerable:true,value:{user:"[email protected]"}}})},logs:[]};</script><script src="/_nuxt/runtime.js" defer></script><script src="/_nuxt/pages/index.js" defer></script><script src="/_nuxt/pages/index.8be2ffa62aee797d62e6.hot-update.js" defer></script><script src="/_nuxt/commons.app.js" defer></script><script src="/_nuxt/vendors.app.js" defer></script><script src="/_nuxt/app.js" defer></script>
Not ideal, but the following works:
<script>
import Logo from '~/components/Logo.vue'
import { User } from '~/queries/auth.graphql'
export default {
apollo: {
user: {
query: User,
prefetch: true,
// The server doesn't get the config, and will continue to prefetch the data
pollInterval: process.server ? undefined: 1000,
},
},
components: {
Logo
}
}
</script>
Brilliant workaround, @paulb896. 🙏
I ended up going with a short-circuit conditional. Works beautifully. Thanks for pointing this out.
<script>
import Logo from '~/components/Logo.vue'
import { User } from '~/queries/auth.graphql'
export default {
apollo: {
user: {
query: User,
prefetch: true,
// The server doesn't get the config, and will continue to prefetch the data
pollInterval: process.client && 1000,
},
},
components: {
Logo
}
}
</script>
I would still say this is a bug that should be fixed. But at least I now know how to work around it.
Just ran into this on version 4.0.0-rc19
I ran into a an issue just now where I had a pollInterval
setup on the parent of a nuxt-child
, and when the route changes to the nuxt-child, the next time the query runs, it crashes with this weird error:
// NOTE logging: graphQLErrors, networkError, operation, forward
Array []
Error
InvariantError invariant.esm.js:12
invariant invariant.esm.js:24
writeFieldToStore bundle.esm.js:664
writeSelectionSetToStore bundle.esm.js:560
writeSelectionSetToStore bundle.esm.js:551
writeResultToStore bundle.esm.js:529
write bundle.esm.js:875
markQueryResult bundle.esm.js:1781
markQueryResult bundle.esm.js:1201
subscription bundle.esm.js:1642
next Observable.js:322
notifySubscription Observable.js:135
onNotify Observable.js:179
next Observable.js:235
next bundle.esm.js:866
next bundle.esm.js:866
notifySubscription Observable.js:135
onNotify Observable.js:179
next Observable.js:235
notifySubscription Observable.js:135
onNotify Observable.js:179
next Observable.js:235
createUploadLink index.js:120
undefined undefined
Whats interesting is if I do something like this:
"$route.params.id"(newVal, oldVal) {
if (oldVal) {
setTimeout(() => {
this.$apollo.queries.tickets.refetch()
}, 1000)
}
}
This runs when you come back from the nuxt-child using ./
in a nuxt-link. I will get the same error with or without the setTimeout. Makes me think this is related to the refetch()
method in Vue Apollo.
My error was due to a GQL query missing an ID.
project {
id # Without this, it caused the above error
timezone
}
I figured it out after trying to figure out how the cache works and triggered another InvariantError that had a better description about missing project resource ID.