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

with-Apollo example makes it impossible to generate static pages #9503

Closed
pkellner opened this issue Nov 23, 2019 · 12 comments
Closed

with-Apollo example makes it impossible to generate static pages #9503

pkellner opened this issue Nov 23, 2019 · 12 comments

Comments

@pkellner
Copy link
Contributor

Feature request

Is your feature request related to a problem? Please describe.

There is no reason that using graphQL with apollo should prevent us from having static rendered pages

A clear and concise description of what you want and what your use case is.
Because with-Apollo uses getInitialProps in the HOC withApollo, even if there is no calls to graphQL that need to be resolved on the server render, a non-static page is generated.

Describe the solution you'd like

I'd like to see with-Apollo modified so that if all the graphQL is rendered on the client, a static page can be rendered. That is, not requiring getInitialProps

@timneutkens
Copy link
Member

@HaNdTriX added a ssr: false option to the withApollo hoc. https://github.com/zeit/next.js/blob/canary/examples/with-apollo/lib/apollo.js#L19

@HaNdTriX
Copy link
Contributor

HaNdTriX commented Nov 24, 2019

I have added the same api to the with-redux example. See the following comment to check out how it works.

#9285 (comment)

- export default withApollo(IndexPage)
+ export default withApollo(IndexPage, {
+  ssr: false
+ })

https://github.com/zeit/next.js/blob/canary/examples/with-apollo/pages/index.js#L29

@pkellner
Copy link
Contributor Author

@timneutkens I thought the rule was that if getInitialProps was mentioned inside of the /pages/mypage.js file that it would not statically generate. I did just test the example and you are correct in saying that it does statically render with that flag set.

@timneutkens
Copy link
Member

@pkellner it checks the method on the function/class being exported, so it's aware of runtime assignment.

@timneutkens
Copy link
Member

@HaNdTriX it's probably a good idea to document this option.

@HaNdTriX
Copy link
Contributor

Oh I just saw that I already documented the most important use cases in here.

I will try to add more docs in the future. As a sneak peek have a look at this:


Render strategies

The HOC withApollo supports multiple render strategies:

  • 1. automatic server side fetch
  • 2. no server side fetch
  • 3. manual server side fetch

1. automatic server side fetch (default)

export default withApollo(PageComponent)

This strategy automatically determines your data requirements on the server using apollos getDataFromTree. Apollo may need to render your app multiple times in order to execute each query. After all queries have been resolved Next.js takes over and renders your app with the state generated from apollo.

2. no server side fetch

export default withApollo(PageComponent, {
  ssr: false
})

This strategy allows you to use Next.js automatic static optimisation feature. The server will render the markup statically without any data. In this case apollo will fetch its data on the client only.

3. manual server side fetch

PageComponent.getInitialProps = async (ctx) => {
  await ctx.apolloClient.query({
    query: gql`
      query allPosts($first: Int!, $skip: Int!) {
        allPosts(orderBy: createdAt_DESC, first: $first, skip: $skip) {
          id
          title
          votes
          url
          createdAt
        }
        _allPostsMeta {
          count
        }
      }
    `,
    variables: {
      skip: 0,
      first: 10,
    }
  })

  return {}
}

export default withApollo(PageComponent, {
  ssr: false
})

This strategy doesn't run apollos getDataFromTree. Instead you can explicitly determine what should be fetched on the server. We only recommend this strategy if you really need to optimize your ssr time.

@timneutkens
Copy link
Member

This will probably also help: #9524

@pkellner
Copy link
Contributor Author

Thanks @timneutkens You've done a great job of articulating where I see issues need to be addressed in how SSR and SSG need to work on a single site. I struggle with how to bring it all together with the two big sticking points for me being authentication and routing in serverless environments. I feel like there is a lot of stuff I don't understand, and when I talk to others smarter then me, they too don't (or can't) articulate how this is all going to come together.

I'm optimistic that you will figure it out and bring it to the masses (me), so we can all consume it and get the bests of SSR and SSG in our apps and not have a heavy express-ssr piece bundled into our SSR end point.

Closing this issue because your #9524 is the better discussion.

@pkellner
Copy link
Contributor Author

@HaNdTriX , I know this is a JavaScript/Redux thing, but still hoping for some help.
I want to use compose with withApollo so I can export withApollo and withRedux. I can't figure out how to pass the ssr parameter when using compose. I tried something like this but it did not work.

const withApollo1 = () => withApollo(Page, { ssr: true });
export default compose(
    withApollo1,
    withRedux
)(Page);

@pkellner pkellner reopened this Jan 25, 2020
@rokinsky
Copy link
Contributor

rokinsky commented Feb 2, 2020

@HaNdTriX I think you forgot Page in the arguments:

const withApollo1 = (Page) => withApollo(Page, { ssr: true });

@pkellner pkellner closed this as completed Feb 2, 2020
@Ajithp
Copy link

Ajithp commented May 5, 2020

Oh I just saw that I already documented the most important use cases in here.

I will try to add more docs in the future. As a sneak peek have a look at this:

Render strategies

The HOC withApollo supports multiple render strategies:

  • 1. automatic server side fetch
  • 2. no server side fetch
  • 3. manual server side fetch

1. automatic server side fetch (default)

export default withApollo(PageComponent)

This strategy automatically determines your data requirements on the server using apollos getDataFromTree. Apollo may need to render your app multiple times in order to execute each query. After all queries have been resolved Next.js takes over and renders your app with the state generated from apollo.

2. no server side fetch

export default withApollo(PageComponent, {
  ssr: false
})

This strategy allows you to use Next.js automatic static optimisation feature. The server will render the markup statically without any data. In this case apollo will fetch its data on the client only.

3. manual server side fetch

PageComponent.getInitialProps = async (ctx) => {
  await ctx.apolloClient.query({
    query: gql`
      query allPosts($first: Int!, $skip: Int!) {
        allPosts(orderBy: createdAt_DESC, first: $first, skip: $skip) {
          id
          title
          votes
          url
          createdAt
        }
        _allPostsMeta {
          count
        }
      }
    `,
    variables: {
      skip: 0,
      first: 10,
    }
  })

  return {}
}

export default withApollo(PageComponent, {
  ssr: false
})

This strategy doesn't run apollos getDataFromTree. Instead you can explicitly determine what should be fetched on the server. We only recommend this strategy if you really need to optimize your ssr time.

I was looking for the 3rd option precisely
Thanks a lot man.

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants