0

I’m using Nuxt which does both static site generation (SSG) and server-side rendering (SSR)

My app hits a graphQL API for content using Apollo smart queries (@nuxtjs/apollo).

Before the API returns I can safely use

{{post}}

Without an errror, but if I do for example

{{post.author.name}}

The app errors with can’t read property of null due to the moment before the API returns.

While this can easily be fixed with either

<template v-if="post && post.author && post.author.name">
    {{post.author.name}}
</template>

Or

{{(post && post.author && post.author.name ? post.author.name : '')}}

…Both of these cause a blink during page load.

Because of SSG, the correct content is already in the DOM. Hydration should have already bound the DOM element to some data. By using either of the above, I’m telling Nuxt to immediately throw out the initial data until the content API has returned. In effect I get a sub-second page-load of the correct content followed by a blank until the API request returns a second or so later.

What I actually want to achieve is this

{{(post && post.author && post.author.name) 
    ? post.author.name 
    : [use what is already in the DOM]}}

or possibly, defer SSR until the Apollo smart query has returned.

How do I handle this momentary lack of data without rendering a blank?

codycustard
  • 448
  • 1
  • 4
  • 10
  • Not sure how you're missing SSR and SSG here. Also, last time I guess Apollo, there was some helpers for that one already. Simplest solution here, if the content doesn't need to be SSR'ed (author's name) is still to wrap that part into a `client-only`. Otherwise, a rehydration will likely cause a flicker indeed, no magic sauce here since you have a difference between the server and client rendered template,. – kissu Aug 25 '22 at 21:45
  • I don't want to use `client-only` as the content needs to be in the DOM for SEO. It's a hypothetical example but in practice this is my default approach where the content needs to be in the DOM to get the benefit of SSG. My understanding is that using `client-only` as a default would be making it more like an SPA – codycustard Aug 26 '22 at 07:38
  • Yep, as the same time: you need some kind of CSS trick/template skeleton or alike to not get a flicker since the content will go from "static from server" to "empty on client" to "populated on the client". If it's needed for SEO (quite strange IMO), so yeah `client-only` is not a viable solution. – kissu Aug 26 '22 at 08:08
  • This IS related to skeleton issues but its not the answer, for example when clicking an item from a listing and hitting back button, in order to maintain correct router scroll position I have to give the listing data an array with length = the `items per page` value and give a fixed CSS height to the listing items. But this is exactly what I'm trying to avoid - if there is correct data already in the DOM from SSG when the page hydrates, I shouldn't have to give an empty fallback in my template, as this is what's causing the blink :/ – codycustard Aug 27 '22 at 09:15
  • IE If the page hydrates and other content on the page is already reactive BEFORE the apollo query returns, is it not possible for the fallback to be the data that is already there? – codycustard Aug 27 '22 at 09:25
  • If you go back, you should totally be able to keep the scroll position. You could use `keep-alive`, or any solution like swvr/vue-query too I guess (if you want something more fine-tuned mostly). You should not need to rely on fixed CSS height (I mean, if by fixed you still mean something relative like `rem` it's fine I guess). I'm not sure if you can pass some data from your server to your client directly with Apollo. For your last comment, I guess it depends on how you handle the call (you can always block the rendering until the Apollo query is done). Highly abstract since no code here. – kissu Aug 27 '22 at 10:02
  • Yes I would much rather not use fixed CSS heights, not least because it is tricky, I've had to use pseudo-elements with padding-top and absolute positioning to maintain the correct proportions across all viewports.. And in some models there is an optional hero element so no way of knowing the height of a placeholder. I would much rather not do this and instead use the SSG content for my placeholders until Apollo returns. – codycustard Aug 30 '22 at 10:35
  • https://www.npmjs.com/package/nuxt-lazy-hydration is the best option I've found to delay hydration until I have content but TBH this feels like a very non-standard approach. I thought the answer was going to be something very simple :/ – codycustard Aug 30 '22 at 10:36
  • You could use `aspect-ratio` for that one too. For the hydration part, Markus' package is indeed the only option regarding this. You have some server-only components in Nuxt3 too but usually, if you want to not have any hydration or to get a fine grained control from a framework, you aim more towards Astro, Qwik, Marko, Fresh, SvelteKit or alike (anything based on Islands Architecture). Nuxt, Next, Gatsby are not well into that right now (yet). – kissu Aug 30 '22 at 11:25

0 Answers0