Hi all,
I’ve been tinkering around trying to learn ssr/apollo client better and was wondering if there is a better solution then what I have. Is there a cleaner way to hydrate the front end client without the use a vuex? I’m also using vueApollo and it says that it attempts to do prefetch automatically but I’m not sure how I would set the APOLLO_STATE.
Dev mode… ssr + pwa
Pkg quasar… v1.0.5
Pkg @quasar/app… v1.0.4
Apollo Boot File
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
import fetch from 'node-fetch'
import { createHttpLink } from 'apollo-link-http'
const createApolloClient = function (ssr = false) {
const httpLink = createHttpLink({ uri: process.env.API_URL, fetch: fetch })
const cache = new InMemoryCache()
if (!ssr && typeof window !== 'undefined') {
const state = window.__APOLLO_STATE__
if (state) {
cache.restore(state)
}
}
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
connectToDevTools: true,
...(ssr ? { ssrMode: true } : { ssrForceFetchDelay: 100 })
})
return apolloClient
}
export default ({ app, Vue, ssrContext }) => {
const apolloClient = createApolloClient(!!ssrContext)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
errorHandler ({ graphQLErrors, networkError }) {
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
)
}
if (networkError) {
console.log(`[Network error]: ${networkError}`)
}
}
})
Vue.use(VueApollo)
app.provide = ({ $apolloProvider: apolloProvider })
if (ssrContext) {
ssrContext.apolloState = JSON.stringify(apolloProvider.defaultClient.extract())
ssrContext.apollo = apolloProvider
}
}
The apolloClient.extract() here always returns {} but I still need to call it here because if ssrContext.apolloState is null quasar complains when it tries to inject apolloState into index.template.html
index.template.html
<% if (htmlWebpackPlugin.options.ctx.mode.ssr) { %>
<script>
window.__APOLLO_STATE__ = {{{ apolloState }}};
</script>
<% } %>
listItems component
<template>
<div class="col">
<ul>
<li v-for="item in listItems" :key="item.id">
<router-link :to="{ name: 'anotherPage', params: { name: item.name } }">{{ item.name }}</router-link>
</li>
</ul>
</div>
</template>
<script>
import GET_LIST_ITEMS from '@graphql/queries/listItems.gql'
export default {
async preFetch ({ store, currentRoute, previousRoute, redirect, ssrContext }) {
if (ssrContext) {
await ssrContext.apollo.defaultClient.query({
query: GET_LIST_ITEMS,
variables: {
where: {}
}
})
ssrContext.apolloState = JSON.stringify(ssrContext.apollo.defaultClient.extract())
}
},
apollo: {
listItems: {
query: GET_LIST_ITEMS,
variables: {
where: {}
}
}
}
}
</script>
Do I have to use quasar prefetch on every component? Is there a cleaner/better way? Am I missing something? This currently works, client properly hydrated, no additional graphql requests, apollo cache is loaded without the use of vuex. I want to use apolloClient for local state management and so it would be better to not have vuex in the build.
Would love your input! Thanks!