Prefetching API Data with Apollo for Nuxt.js SSR - vue.js

I've got what is hopefully a very simple question about prefetching data from within an apollo/nuxt configuration.
I am requesting data from a GraphQL API and want to prefetch the data to use server-side rendering. Reading the docs it seems like I should simply be able to set prefetch: true on my apollo query but this is not working – it is always sending the request from the client side which is causing all kinds of issues.
Here is the code in my component:
apollo: {
concept: {
prefetch: true,
query: conceptStatements,
variables () {
return { id: this.$route.params.id }
}
}
}
I feel like it will have something to do with when this.$route.params.id is evaluated?
Ultimately I would like to create a Vuex store in the store/index.js which takes all of my apollo queries and renders the data in them accessible across the application but the documentation is very vague on how I might do this. Any help would be much appreciated!

Are you really sure your data is not prefetched?
Prefetch is for the first rendering (in SSR mode) ; Nuxt/Apollo call your graphql api, generate the page and send it to the browser. If you just navigate to your page from another route, nuxt call your api from the browser.
You can check this behavior in devtools/network, select xhr. Refresh your page, there is not xhr call. Go to another route and refresh your page, then navigate to your route where is your apollo query and you should see a xhr call to your graphql api.
Also, you can configure this behavior in your apollo config with fetchPolicy.
You don't need Vuex to store response of your apollo queries:
From vue-apollo doc:
When you perform GraphQL queries with Apollo, the results of API calls
will be stored in Apollo cache. Now imagine you also need to store
some kind of a local application state and make it available for
different components. Usually, in Vue application we can achieve this
with Vuex. But having both Apollo and Vuex will mean you store your
data in two different places so you have two sources of truth.
So, if your perform same query from different page or component, Apollo don't call your api each time, but retrieve data from the Apollo cache. Apollo is just magic!

Related

Using Vue Composition API with Pinia

I have a Vue 3 project and I'm working with Composition API. I'm communicating with my backend using Urql which is a graphql library which allows me to wrap API requests as composables.
I'm new to Pinia, but after a bit of time working with Vue 2 + Vuex I can tell that one of the most common scenarios of writing actions was making API requests and updating the state (asynchronously) with the response. I'm trying to adopt the same technique in my current tech stack and facing some issues.
My problem is that I can't just use the old fashioned fetch/axios/got libraries to execute requests whenever I want, I should first register the composable somewhere. I've seen that one option is to call the composable's use* function in the store's state section, but it seems weird to me to have such thing in there as it has nothing to do with the state. I've tried executing the use* method directly in an action, but it seems to fail.
I wonder if I'm missing some best-practice way to work with Urql and Pinia, as things are getting more and more complex even though my usecase is pretty common and simple. Should I use Urql's Client directly? Any other good solution to make gql requests from within my store actions?
export const useUsersStore = defineStore('app', {
actions: {
setUser() {
const response = (await useUsers()).data // this wont work
},
}
);

How to return Vuex-generated page to client on initial Vue load?

I have a Vue / Nuxtjs app which displays lots of user-provided content (think of it as a crowdsourced blog). The content on the client is retrieved and stored in Vuex. When a page is loaded, it displays the current content and then uses fetch to get the updated data. Here is a typical component:
fetch() {
this.$store.dispatch('feeds/refreshLatest')
},
computed: {
feed() {
return this.$store.state.feeds.latest
}
}
where feeds/refreshLatest uses axios to retrieve the posts.
This works quite well. The problem is the initial load is very slow, especially on the front page which has to process and display dozens of articles.
I have SSR enabled, and would like the server to store the content, and then on initial load provide a rendered page to the client. However, the Vuex object on the server seems to be new for each request, and so the client has to wait for the entire set of articles to be fetched before anything is displayed, which is unacceptable. Doing all the fetches only on the client solves this problem, but it is still too slow.
I thought I could somehow use the same server Vuex on each call and sending it to the client with nuxtServerInit, but I don't see a way to achieve sharing the Vuex. Thank you for any pointers or other packages which could help.
The question is that after the fetch is finished after the api call in the server rendering, the DOM is dropped to the client, and the process is running every time and slow?
I solved similar issues using cookies. This is because cookies can also be used to render servers. I used the method below.
Store the data in the cookie after the initial api call, and send the data in the cookie to the client first.(If cookies are present, do not call api from server)
Call api from client to update data.
I use this library.
https://github.com/microcipcip/cookie-universal/tree/master/packages/cookie-universal-nuxt#readme

Where does Vuex store reside in Nuxt

Just trying to get my head around Vuex / Nuxt , also quite new to nodejs.
Given that nuxt is a server side rendering app , Where does Vuex "reside" . In standard Vue , Vuex is a client side store. How does it work in Nuxt? Is it still a client side store but just rendered on the server first?
If it stays on the server , then I am just wondering how it handles per user data - or is it somehow shared. thank you.
SSR and rehydration:
Both client and server hold the state. When the client makes the first request to load the initial page the state is usually passed through the html document inside a script, something like:
<script type="text/javascript" defer>window.__NUXT__={"data":[{"name":"server"}],"error":null,"serverRendered":true}</script>
Then when the application js load it has to pickup the state, this processed is known as rehydration. From this point the client will maintain the server state in sync.
Nuxt specifics:
Interesting parts of Nuxt documentation:
https://nuxtjs.org/guide/async-data
https://nuxtjs.org/guide/vuex-store
Nuxt Vuex Demo:
https://nuxtjs.org/examples/vuex-store
Vue SSR:
In addition take a look into vue ssr documentation, it's very detailed and it does a better job explaining how everything fits in:
https://ssr.vuejs.org/en/hydration.html
https://ssr.vuejs.org/en/data.html
we will serialize and inline the state in the HTML. The client-side store can directly pick up the inlined state before we mount the app.

How to update graphql endpoint (not using Graph.cool)

I spent some time working through the ReactQL starter kit and watched the intro video outlining how the kit is set up, but one area I am still confused on is where to put our graphql specific stuff if we don't use a Graph.cool endpoint.
Graph.cool seems great, but to get more experience with Graphql, I want to set up my own schema, queries, etc.
What is the best practice for handling our own graphql stuff? Do I place the:
app.get('/', {
graphiql: true
})
or Koa equivalent in the config/project.js APOLLO variable? I am more familiar with Express than Koa, but could also see it going in the entry/server.js file.
The GraphQL endpoint is set in config/project.js, under the APOLLO variable by default:
export const APOLLO = {
uri: 'https://api.graph.cool/simple/v1/cinomw2r1018601o42x5z69uc',
};
Change APOLLO.uri to point to another GraphQL server will update both the server and browser environments to use that new server.
If you want to create your own GraphQL server alongside the front-end web server that ReactQL starts by default, there's an example you can see here for wiring up your own schema and GraphQL endpoint:
https://github.com/reactql/examples/tree/master/graphql-server
(Usage instructions for example projects can be found here)

How do you pass data to react components from express or koa without renderToString?

I'm unable to use React's server side rendering due to my use of client side libraries such as reqwest. I would like to pass some data to my react components, however. Is there a way to do this?
The easiest way to do this is by having api-client.js and api.js. In your browserify/webpack config you set up a client side version. For browserify put this in your package.json (feel free to edit and add webpack).
"browser": {
"./path/to/api.js": "path/to/api-client.js"
}
The second option is better in my opinion, but more difficult to implement. You create an abstract representation of your API that works like this:
var comments = require('./api').get('comments');
comments.getById('7').then(function(comment){ ... });
comments.create({...}).then(...);
On the server api.js simply calls the correct functions, which all return promises. On the client it returns a promise, makes an ajax request to the server, which calls these functions, and sends back the response, and the api client resolves/rejects its promise.
This allows the api to automatically work, and allows you to do additional things like track unfulfilled promises, and pre-populate state on the client, etc. (see react-async for example).