Apollo-client: SSR stopped working in Next.js app from @apollo/client-beta.8

Created on 10 Jun 2020  路  21Comments  路  Source: apollographql/apollo-client

Intended outcome:

When following the next.js with-apollo example using @apollo/client-beta.8 or any newer client in ssrMode, we should see the loaded GraphQL data in our markup when we view the page source.

Actual outcome:

When we inspect the page source, the markup shows that our page is in a loading state.

How to reproduce the issue:

Use beta.8 or greater in the next.js with-apollo example. The last two commits in the repo included below will show the viewed source of a page including markup in a loading state when using beta.8, and returning the expected markup with GraphQL supplied data in beta.7.

https://github.com/lyonsv/with-apollo-app

A quick sample of a few versions before 7 suggest this is a regression in introduced between 7 and 8. Glancing at the commits between the two versions, there's a lot going on and there's nothing obvious to me that could be the cause.

The commits where the the problem occurs should be identifiable below:

https://github.com/apollographql/apollo-client/commits/ab0bbe2f5b06465c9c54de8c633e119e21881504

The problem was raised by tests that I have written in Cypress inspecting the request, and on my express server used in Next.js. Happy to contribute similar tests to prevent this regression from occurring again - it's a hard one to spot.

Versions

System:
OS: macOS 10.15.5
Binaries:
Node: 14.2.0 - /usr/local/bin/node
Yarn: 1.7.0 - ~/.yarn/bin/yarn
npm: 6.14.4 - /usr/local/bin/npm
Browsers:
Chrome: 83.0.4103.97
Firefox: 65.0
Safari: 13.1.1
npmPackages:
@apollo/client: 3.0.0-beta.8 => 3.0.0-beta.8

has-reproduction 鈿涳笍 React-related 馃摕 regression

Most helpful comment

Although this issue is resolved, I seem to have used some keywords that will lead people here for reasons that are more to do with the next.js examples, than with apollo client. Summary of my knowledge below:

  1. Up until early 2020, Next.js included a complex example for how to use Apollo with SSR. It looked something like this.
  2. In migrating from Apollo client v2 -> v3, an SSR/Apollo/Next.js setup that follows the original Next.js with-apollo example could break your SSR.
  3. In order to not return loading state markup from the server, it's now necessary to check if useQuery is returning both loading and data is undefined if (!data && loading) { return <Loading />}, before returning your component that uses loaded data. Any Apollo/client version greater than beta.23 should be fine.
  4. At this point, it looks probable that a lot of code can be deleted if you use the latest version of apollo-client v3 and SSG, which you get a sense of from the latest with-apollo example. This example would not work with apollo client v3, because it just checks if the state is loading on the server - and not if !data. It works fine if you add the !data check

Point 3 is going to catch a lot of people, as you won't spot that SSR is broken in the browser or in your test suite, unless you test the body of the response to a request - which I'd recommend doing. I had the inelegant cypress test below in my code base, and it did the job:

describe('a ssr request visits homepage', () => {
  it('sees the hero section of the app', () => {
    cy.request(routes.home).as('homepage')
    cy.get('@homepage').should(response => {
      // home-content-desktop should be visible in loaded state
      const ssrHero = response.body.search('home-content-desktop')
      // if it was not visible, a search for the string position within body would return -1. 
      expect(ssrHero).to.not.eq(-1)
    })
  })
})

All 21 comments

@lyonsv which version of @apollo/react-ssr are you running? I was using 3.1.5 and I had my data missing too.
When I bumped it to 4.0.0-beta.1 it fixed my problem.

@capaj the problem seems to be independent of @apollo/react-ssr. This issue was created to focus on the SSR problem that's replicable in https://github.com/lyonsv/with-apollo-app by moving from the most recent commit (broken) to the previous commit (working). These two commits show that @apollo/client-beta.8 and greater will return markup in a loading state in the with-apollo next.js example, and every release from beta.7 backwards returns markup containing the loaded data.

In my actual production project I was using the 4.0.0-beta.1 of @apollo/react-ssr and SSR was still broken when used with '@apollo/client' 3, but I think the example repo that I've created better explains the problem...because I've all sorts of things going on in my production project that I think obfuscate the issue.

I could also reproduce it with "@apollo/client": "3.0.0-rc.3", and -rc.4

Any combination of versions that works? I'm missing server-side rendering for a long time now, as it's not working for me since ~v2.

Similar issue: https://github.com/apollographql/react-apollo/issues/3678

In my example SSR works for beta 7 and below. I would imagine a lot of other things do not work in a release that far back.

Curiously, in the issue you鈥檝e linked to, it鈥檚 describing a problem for a version before beta 7, but maybe it鈥檚 not the same problem.

I鈥檇 suggest rolling back to v2 of Apollo client to get everything working if you need SSR immediately. There might be some work in rolling back as @Apollo/client v3 replaces a few packages, but rolling forward again once this issue is resolved should be straightforward.

Thanks, I tried beta 7 again and fixed some dependencies and SSR worked. On a side note, looks like Next.js won't support getDataFromTree anymore...

@renato my example is using the updated with-Apollo example that the Next.js team merged several days ago. It鈥檚 dramatically simpler, and doesn鈥檛 use getDataFromTree. I鈥檝e yet to try and update the code in my production app to make use of SSG, but you鈥檙e correct that some changes will need to be made - it鈥檚 looking like those changes will involve a lot of code deletion, which would be be nice.

I鈥檇 recommend rolling everything back to Apollo Client 2 for the moment, and not to use beta.7. The git commits between that release and the current RC suggest lots of bugs have been found and fixed over the last few months.

I think using apollo with nextjs was a wrong decision altogether :(

@jsartisan my experience has been that both are magic technologies when applied to suitable problems. The current with-Apollo example from next.js shows a pretty simple example of how to get them to work together with Apollo client 2

Switched back to apollo-boost for SSR.

@jsartisan can you elaborate little more on how switching to apollo-boost worked? iam using next.js and struggling to get SSR working with apollo , what versions of apollo-client and next.js are you using? are you following the new example or getDataFromTree?

@msreekm Unfortunately the current next.js apollo example got a lobotomy and isn't practical to refer to for how bigger companies are currently using next with apollo and ssr.

I think this example is probably a good starting point for anyone wanting to get started with next and apollo:
https://github.com/vercel/next.js/discussions/11957#discussioncomment-27012

Hi @lyonsv! I pulled down the reproduction and tested it with the lasted release 3.0.0-rc.8 and it appears to resolve the issue. Could you double-check that it does?

Hi @nodabladam ,Thanks for the link. i will give it a try.

just worried that if we still get Apptree working now , timneutkens mentioned in the same thread that it may break in near future ? do you still recommend this approach?

https://github.com/vercel/next.js/discussions/11957#discussioncomment-29427

@jcreighton I'm still seeing "Loading" in the page source, and not the markup that should should have been generated.

The steps I've followed to reproduce are:

  1. In package.json, change @apollo/client from 3.0.0-beta.8 to 3.0.0-rc.8
  2. Run npm i
  3. rm -rf .next (just in case)
  4. npm run dev
  5. visit view-source:http://localhost:3000/

This produces the markup pasted below. Did you see markup returned from the server that included the loaded graphql data? Maybe I need to dig around a bit more - and clear a few other things that could be cached.

image

@lyonsv The difference between beta.7 and beta.8 is the PostList component is receiving its data vs not (the query succeeding in index.js in both versions). That issue is resolved as of beta.23. What you're encountering now is related to loading being set to true on the server, see https://github.com/apollographql/react-apollo/issues/3338#issuecomment-528462945 and https://github.com/apollographql/react-apollo/issues/3338#issuecomment-571854056. On this line, you'll want to check if !data in addition to the loading states. Then you'll see the markup as expected.

That makes sense, thanks @jcreighton . A check for !data solves the problem using the latest release candidate.

@lyonsv Thanks for the quick reply to @jcreighton's questions! Glad this is resolved for you.

@msreekm @nodabladam @jsartisan Mind taking your discussion somewhere else?

@benjamn Sorry benjamn for the noise. The latest next apollo example makes SSR stop working in certain cases for existing apps and I linked to a thread about that to prevent people from saying this still isn't working for the wrong reasons but I should have been alot more clear about that in my post.

So checking for!data before the loading check solves the issue for us as well, but it's a bit disturbing that the semantics of "loading" have changed. I suspect this is going to cause a lot of headache for people migrating to 3.x.

Although this issue is resolved, I seem to have used some keywords that will lead people here for reasons that are more to do with the next.js examples, than with apollo client. Summary of my knowledge below:

  1. Up until early 2020, Next.js included a complex example for how to use Apollo with SSR. It looked something like this.
  2. In migrating from Apollo client v2 -> v3, an SSR/Apollo/Next.js setup that follows the original Next.js with-apollo example could break your SSR.
  3. In order to not return loading state markup from the server, it's now necessary to check if useQuery is returning both loading and data is undefined if (!data && loading) { return <Loading />}, before returning your component that uses loaded data. Any Apollo/client version greater than beta.23 should be fine.
  4. At this point, it looks probable that a lot of code can be deleted if you use the latest version of apollo-client v3 and SSG, which you get a sense of from the latest with-apollo example. This example would not work with apollo client v3, because it just checks if the state is loading on the server - and not if !data. It works fine if you add the !data check

Point 3 is going to catch a lot of people, as you won't spot that SSR is broken in the browser or in your test suite, unless you test the body of the response to a request - which I'd recommend doing. I had the inelegant cypress test below in my code base, and it did the job:

describe('a ssr request visits homepage', () => {
  it('sees the hero section of the app', () => {
    cy.request(routes.home).as('homepage')
    cy.get('@homepage').should(response => {
      // home-content-desktop should be visible in loaded state
      const ssrHero = response.body.search('home-content-desktop')
      // if it was not visible, a search for the string position within body would return -1. 
      expect(ssrHero).to.not.eq(-1)
    })
  })
})
Was this page helpful?
0 / 5 - 0 ratings

Related issues

rafgraph picture rafgraph  路  3Comments

helfer picture helfer  路  3Comments

gregorskii picture gregorskii  路  3Comments

stubailo picture stubailo  路  3Comments

stubailo picture stubailo  路  3Comments