apollo icon indicating copy to clipboard operation
apollo copied to clipboard

SSR Data are loaded only after refresh (SSR BUG related with useAsyncData - so every composable)

Open MojoDeMedici opened this issue 3 years ago • 7 comments

Environment

  • Operating System: Darwin
  • Node Version: v18.13.0
  • Nuxt Version: 3.1.1
  • Nitro Version: 2.1.1
  • Package Manager: [email protected]
  • Builder: vite
  • User Config: debug, ssr, css, build, vite, modules, runtimeConfig
  • Runtime Modules: ()
  • Build Modules: -

Describe the bug

Fetching data from Apollo server works only after refresh. On Page loading, the setup function doesn't fire the request to the Apollo server, but it waits until a refresh is performed. The request then appear in the console network, and everything works fine (on page loading the request/fetch doesn't exist).

This happens only when the ssr option is set to true in nuxt.config (by default it is set to true). The behavior changes, and the fetch is performed also on page load when the ssr option is set to false (clearly).

Expected behaviour

I would expect that the first time I load a page, the request is normally performed to the apollo server, in this way I can populate the page with the data.

Reproduction

Someone in December opened an issue and tagged it as BUG, unfortunately the issue was closed just before the end of the year without a real resolution. For reference the following is the link to the issue: https://github.com/nuxt-modules/apollo/issues/452#issue-1451729190

Additional context

I tried to investigate a bit the issue, and I noticed that under the hood, the module uses the useAsyncData (form the nuxt composable). This is amazing but it's worth probably point out that (the yellow alert in particular):

Screenshot 2023-02-02 at 6 47 46 PM

Maybe the problem is just here??

Logs

No response

MojoDeMedici avatar Feb 02 '23 23:02 MojoDeMedici

The way in which I "hacked" this is issue is the following:

<script setup>
  const query = gql`
    query getCategories {
      categories {
        data {
          id
          attributes {
            name
          }
        }
      }
    }
  `
const { data, refresh } = await useAsyncQuery(query)
if (!data.value) {
    refresh()
  }
</script>

So I am conditionally refreshing the data if they are indeed null. This trick allow me to perform the SSR :)

Maybe it's worth allowing an automatic refresh option when data are null and contemporarily we are using SSR.

MojoDeMedici avatar Feb 03 '23 00:02 MojoDeMedici

@Dinuz can you share apollo config in nuxt.config.ts and @nuxtjs/apollo version?

i used node v18.12.1 @nuxtjs/apollo": "5.0.0-alpha.5 " nuxt": "^3.1.1" nuxt3": "3.1.2-rc.0-27922414.cb0860b"

export const getUsersQuery = gql`
  query users(
    $limit: Float
    $orderBy: [UserOrderByInput!]
    $page: Float
    $where: UserWhereInput
  ) {
    users(limit: $limit, orderBy: $orderBy, page: $page, where: $where) {
      pageInfo {
        page
        limit
        currentPage
        totalCount
      }
      docs {
        id
        firstName
        lastName
        email
        username
        roles
        avatar
        status
      }
    }
  }
`

/**
 * query data my user
 * if @data null return login
 */
const variables = {
  limit: 10,

  page: 1,
}

const { data } = await useAsyncQuery(getUsersQuery, variables)
if (!data.value) {
  navigateTo('/user')
}
const users = JSON.parse(JSON.stringify(data.value)).users

mine still return normal.

devhoangkien avatar Feb 03 '23 07:02 devhoangkien

@devhoangkien sure (what do you mean still return normal??),

node version 18.13.0 "@nuxtjs/apollo": "^5.0.0-alpha.5" "nuxt": "^3.1.1"

my nuxt.config is super basic:

export default defineNuxtConfig({
  debug: true,
  ssr: true, 
  modules: ['@nuxtjs/apollo',],
  apollo: {
    clients: {
      default: {
        httpEndpoint: 'http://localhost:1337/graphql',
      },
    },
  },
})

MojoDeMedici avatar Feb 03 '23 21:02 MojoDeMedici

I was having the exact same issues here but ensuring I was on beta-5 of nuxt apollo and nuxt 3.1.2 and everything began working as expected.

dolbex avatar Feb 08 '23 19:02 dolbex

Context

I use a Laravel Lighthouse backend and this only occurs to me when auth is required.

System and versions
Operating System: Windows 10 Pro
Node Version: v19.6.0
Nuxt Version: ^3.5.2
Nitro Version: 2.4.1
Package Manager: [email protected]
Builder: vite
@nuxtjs/apollo: 5.0.0-alpha.6
My nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  modules: ["@nuxtjs/apollo"],
  apollo: {
    clients: { 
      default: {
        // Tried this too but results in same behavior.
        // httpLinkOptions: { 
        //   credentials: "include" 
        // }, 
        httpEndpoint: "http://myapp.test/graphql" 
      } 
    },
  },
});

Behavior

If I protect the query (requiring auth) It does not load on initial load (like after refresh). Only when I manually press a button to request the data when the page has been loaded.

If I remove the protection from the query (no auth required anymore) Everything works as intended. It does work on initial load and after refresh.

Visual example of behavior

nuxt-apollo Removing the guard makes it work for ssr, but leaves the query unprotected.

It appears when the server is making the request it does so without auth. But I'd like to be able to protect my queries and have them loaded on initial load when authenticated.

The only way to get data is by calling the refresh method returned by the query method.

Workaround

Adding a plugin utilizing the apollo:auth hook and setting the token from the cookie seems to fix this issue for me in this case:

// plugins/apollo.ts

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('apollo:auth', ({ client, token }) => {
    // access cookie for auth
    const cookie = useCookie(`apollo:${client}.token`)

    // apply apollo client token
    token.value = cookie.value ?? null
  })
})

Other

  • I noticed useLazyAsyncQuery documentation shows useAsyncQuery instead of useLazyAsyncQuery in the example.
  • Using useQuery throws a 500 with message "Unauthenticated" which I assume is intended behavior if unauthenticated, but in this case I am authenticated.

sneakylenny avatar Jun 06 '23 09:06 sneakylenny

I have a similar issue as @timyourivh, but in my case it works on refresh(SSR) and not on the client side. I am using the apollo:auth hook inside plugins/apollo.ts like so:

export default defineNuxtPlugin((nuxtApp) => {
    const { value } = useCookie("session_token");
    nuxtApp.hook("apollo:auth", ({ client, token }) => {
        token.value = `Bearer ${value}`;
    });
});

This works fine for SSR requests (like on refresh), but returns Bearer undefined for client side requests, like navigating between routes.

How can I get the cookie to work for client side requests? Any ideas?

bask-digital avatar Jun 08 '23 16:06 bask-digital

Saw that I replied in this thread and encountered this same thing not that long ago, again. This time I ended up solving it with using a solution similar to a solution mentioned in this comment: https://github.com/nuxt-modules/apollo/issues/312#issuecomment-2007195065 Hope this helps anyone solve this.

sneakylenny avatar Jul 22 '24 15:07 sneakylenny