Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question - Is there support for @nuxtjs/apollo? #70

Open
aaronLejeune opened this issue Aug 23, 2024 · 1 comment
Open

Question - Is there support for @nuxtjs/apollo? #70

aaronLejeune opened this issue Aug 23, 2024 · 1 comment

Comments

@aaronLejeune
Copy link

Hello,

TLDR; how can I enable SSR caching with Apollo combined with NuxtHub?

First of all, I want to say that I’m relatively new to caching and I’m currently trying to optimize the performance of my website.
I’m using Strapi as a headless CMS and fetching content via @nuxtjs/apollo. The project is a webshop that operates in multiple languages and regions, which means a lot of dynamic content and API calls. I noticed the initial response time was realllllyyy slow, so I thought of caching some data on the server frontend as well..

I’ve started testing out NuxtHub, which looks like a great solution for easily storing cache and KV. However, I’m having trouble understanding how to properly cache the API data on the server side. The client-side caching, handled by Apollo itself, is working nicely as expected, but I want to extend caching to the server to improve performance even further.

This is a simplified version of what my current [...slug].vue looks like:

<script setup>
import GetContentBySlug from "~/apollo/queries/delta.gql";

//Fetch and client-cache the data from Strapi
const { data } = await useAsyncQuery({
  query: GetContentBySlug,
  variables: {
    slug: generateSlug(route.params.slug),
    locale: localeProperties.value.locale_strapi,
    market: localeProperties.value.country,
  },
  cache: true,
});

//to set the i18n params in different locales
setI18nParams(data.allLocaleParams);
useSeo(data.seo)

</script>
<template>
  <div>
    <h1>{{ pageData.value.title }}</h1>
    <p>{{ pageData.value.description }}</p>
  </div>
</template>

I’ve done quite a bit of research, but I think I’m stuck and could really use some guidance.
Any help or pointers would be greatly appreciated!

Thanks a lot in advance!

@aaronLejeune aaronLejeune changed the title Question - Is there support for @nuxtjs/apollo Question - Is there support for @nuxtjs/apollo? Aug 23, 2024
@dulnan
Copy link
Owner

dulnan commented Aug 25, 2024

So, what you likely need is the useDataCache composable. If you want to cache most of your GraphQL queries, then it probably makes sense to create your own composable that acts as a wrapper around useDataCache, useAsyncData and useQuery.

However, I'm not entirely familiar with @nuxtjs/apollo because I maintain my own Nuxt GraphQL client. As you mentioned, Apollo has a client cache; I'm not sure if this exclusively only applies to client side or if it would be possible to provide your own "cache provider" so to say? If yes, then you could actually "hook" into this part of Apollo and use useDataCache there to get and set responses into cache. That way you could easily continue to use the default composables and the caching would happen "automatically" in the background, basically.

But assuming this is not easily possible, then a custom composable is the way to go. However, it can get tricky to get the types right, together with useAsyncData and the GraphQL types. I quickly looked at the implementations of useQuery and useAsyncQuery, however not all of the types seem to be properly exported (but I did not check 100%). So this is what a custom composable might look like, as a very rough, non-working starting point:

import { useAsyncData, type AsyncData } from '#app'
import { hash } from 'ohash'

export function useCachedQuery<TResult, TVariables extends OperationVariables>(
  document: DocumentParameter<TResult, TVariables>,
  variables?: VariablesParameter<TVariables>,
): AsyncData<TResult, unknown> {
  // Create a unique key.
  const key = hash(document, variables)
  
  return useAsyncData(key, async function (app) {
    // Try to get from cache.
    const { value, addToCache } = await useDataCache<TResult>(
      key,
      app?.ssrContext?.event,
    )

    // If we have a value from cache, return it.
    if (value) {
      return value
    }

    // Make the GraphQL query.
    const result = await useQueryImpl(document, variables)

    // Add to cache.
    await addToCache(result)

    // Return the value.
    return result
  })
}

If you also want to implement the options of useAsyncData (such as transform or getCachedData), then it gets even more trickier. I have done something similar with the useCachedAsyncData composable that is provided by this module. Maybe this could also be a good starting point for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants