vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.07k stars 27.01k forks source link

Update examples with getInitialProps to SSG #11014

Closed lfades closed 4 years ago

lfades commented 4 years ago

With the release of Next.js 9.3 we are empowering all Next.js applications to take advantage of the JAMStack, before this, around half of our examples were using getInitialProps for data fetching in pages, and even though we are not removing it any time soon, it's not ideal for most applications. You can read more about this here.

Around half of our examples (110+) are using getInitialProps. and in most of those examples it can be replaced with getStaticProps to take advantage of SSG.

Any updates to take advantage of SSG in current examples using getInitialProps are deeply welcome and will be merged ASAP

PRs for New examples using getStaticProps / getStaticPaths and removal of current examples that are very outdated or not worth upgrading are also very welcome.

Here are some of the examples currently using getInitialProps:

https://github.com/zeit/next.js/tree/canary/examples/amp-first https://github.com/zeit/next.js/tree/canary/examples/analyze-bundles https://github.com/zeit/next.js/tree/canary/examples/api-routes https://github.com/zeit/next.js/tree/canary/examples/auth0 https://github.com/zeit/next.js/tree/canary/examples/blog-starter https://github.com/zeit/next.js/tree/canary/examples/custom-server-express https://github.com/zeit/next.js/tree/canary/examples/data-fetch https://github.com/zeit/next.js/tree/canary/examples/ssr-caching https://github.com/zeit/next.js/tree/canary/examples/using-router

To find more examples, do a global search inside our examples for getInitialProps, and with the exception of pages/_document.js any other result is one that we don't want!

If an example can only work with getInitialProps, updating it to use getServerSideProps is also welcome.

Update: Please create a PR per example update, this will speed up the review and merge process :pray:

samao commented 4 years ago

This new feature doesn't seem to work with saga and redux now

timneutkens commented 4 years ago

Updated a bunch of examples in this PR: https://github.com/zeit/next.js/pull/11136

merelinguist commented 4 years ago

Examples still using getInitialProps

Icehunter commented 4 years ago

You may say it's not ideal but it actually is in most cases. There are definitely pure use cases for static vs server-side but there's also the use case of wanting to SSR for bots/SEO and at the same time use CSR after the initial page load.

Any site that relies on SEO but also relies on having a fast experience would benefit from this.

getInitialProps solves this by being called on the server for the first rendering of the site (regardless of page) and all subsequent page navigation will be CSR.

Is there really a desire not to have it be a hybrid like it was?

lfades commented 4 years ago

@Icehunter We have SSG with getStaticProps and getStaticPaths, you can read more about it here. It allows you have very fast static sites with very good SEO, without the drawbacks of SSR.

For most use cases SSG is the better option, even for dynamic sites, and we will keep improving it. Check the RFC for Incremental Static Generation

Icehunter commented 4 years ago

That still won't work for our use cases and how the site exists currently and functions. Is there a way to flag to nextjs to only export the getServerSideProps function if it's actually running under the server with process.X?

We would have to build each page on every visit to the page and every call to the page. Imagine a online store, with a filter tray. We want the store page to render based on a slug for SEO. When a user visits that page and adjusts filters, or clicks another link in the slug; we want client side rendering to take over, present a loader and adjust it as needed by actually changing the slug.

I do that now and we have getInitialProps as part of the process along with swr on a useEffect for changes.

How is that supposed to work when 9.3 is implementing functions that only let you choose one or the other?

lfades commented 4 years ago

@Icehunter What you are saying is completely compatible with SSG, and it works better with SSG.

"We would have to build each page on every visit to the page and every call to the page" - With SSG you do this at build time, and then after revalidation (with the Incremental Static Generation RFC), the same static output can be used to serve all your users and they would never have to wait for a function to be executed, which is what happens with SSR, where a serverless function is executed for every request, being slower and more expensive.

If you still have issues understanding SSG please continue the discussion on the threads related to SSG or start a new discussion so we can stay on topic in this issue :pray:

hatchli commented 4 years ago

Any chance the aws-amplify example could be updated? Working with next and amplify together is already sort of painful, so any direction would be appreciated!

lfades commented 4 years ago

@hatchli It should be possible :+1:. You're welcome to open a PR to update it!

hatchli commented 4 years ago

@lfades You presume I know what to do! Haha but I am running through a few tutorials and seeing what I can learn and make work - if I can figure it out, and also figure out how to do a PR (never done that before) I would certainly like to contribute!

lfades commented 4 years ago

@hatchli No pressure, you shouldn't feel obligated to do anything, take your time to learn and figure out how to make a PR.

The first PR is hard, but we have to start somewhere, so once you know how, start doing.

This is a request for community PRs as we have many examples so anyone is welcome to contribute, I'll do my best to review the PRs and to manually update the examples too :+1:

alejandronanez commented 4 years ago

Hey @lfades, this is a great initiative thanks for surfacing this kind of issues for newcomers 👏.

I've been working on an example that uses urql and getStaticProps, would it make sense to have that example as other graphql examples already exists?

Thanks!

lfades commented 4 years ago

@alejandronanez If we don't have an example for it, it's welcome! make it simple and static 🥂

todortotev commented 4 years ago

@lfades I believe most of the examples are updated as of now. If I missed any, please let me know which so I fix them.

lfades commented 4 years ago

@TodorTotev Redux examples will still use SSR for pages without SSG, which is not ideal, I would prefer an integration like this one: https://github.com/vercel/next.js/tree/canary/examples/with-redux - Doesn't use getInitialProps in _app or a redux wrapper.

dvakatsiienko commented 4 years ago

@TodorTotev in with-redux example there is also withRedux hoc seems to be not used in an example.

also in with-apollo-and-redux getInitialProps is used.

lfades commented 4 years ago

@dvakatsiienko Oh... I'll remove that file 😅. with-apollo-and-redux is missing an update indeed.

dvakatsiienko commented 4 years ago

thank you guys for a great improvements here, observing your work with excitement and using your ideas in our project @TodorTotev @lfades

todortotev commented 4 years ago

@dvakatsiienko Im glad you like it!

@lfades I have spent the last few hours trying to figure out how to strip the "getInitialProps" from the withApollo hook @with-apollo-and-redux example. If you've got a min @ slack - I've sent you a message or if you prefer I can lay out my concerns here.

todortotev commented 4 years ago

Any more examples using getInitialProps?

lfades commented 4 years ago

@TodorTotev

todortotev commented 4 years ago

@lfades I'll get the rest done. Starting tomorrow.

~with-aws-amplify-typescript~ ~with-cookie-auth-fauna~ ~with-firebase-authentication~ ~with-react-relay-network-modern~ ~with-rematch~

lfades commented 4 years ago

@jaydenseric Do you think you can update the with-graphql-react example to match our current GraphQL examples that no longer use AppTree or getInitialProps?

jaydenseric commented 4 years ago

@lfades I have no intention of moving away from getInitialProps — it's far better performance not to have an extra round trip to the app server when navigating to a page client-side. The with-graphql-react example does need to be updated though, since it uses next-graphql-react v5.0.0, the latest is v7.0.1. The setup is a bit easier now; there is no need to decorate the Webpack config. Also cross-fetch can be removed from the example since Next.js handles polyfilling fetch now.

I do plan to make the withGraphQLApp decorator also support use on pages, not just App. That way people who want some pages to use GraphQL, and others to be static can do so. It's not a high priority though, because literally no one I know has a page on their site that has zero GraphQL queries and it's actually nice that all pages are opted out of SSG - I've had problems before where Next.js would render pages statically that should not have been. The sorts of apps I build tend to have user account menus in the global header for example.

lfades commented 4 years ago

@jaydenseric Understood, no pressure on updating the example, thank you for the detailed answer 😌

Not sure about why do you prefer getInitialProps. You're always going for static content as users won't ever hit a serverless function, even when fetching data for the page (the json data is also cached), and getting static content should be much faster than waiting for a serverless function.

Even if getInitialProps runs in the client for page navigations, it'll most likely make a call to an API to get some data, but with SSG that same data can be cached just like the HTML of the page.

todortotev commented 4 years ago

I think officially there are no more examples to be reworked? 🚀

lfades commented 4 years ago

@TodorTotev I can do another look up after I finish revieweing the current PRs you did 😌

Usually I just do a global search for getInitialProps, and any result that's not in _document.js or _error.js is a likely match.

yassinebridi commented 4 years ago

I think officially there are no more examples to be reworked?

there is Algolia

https://github.com/vercel/next.js/blob/canary/examples/with-algolia-react-instantsearch/pages/index.js

Albert-Gao commented 4 years ago

Thanks for the works.

I have a doubt over few changes here like the one for with-apollo

Do we really need to remove the original examples?

For example, the original with-apollo works perfectly fine. And I am using expo web with next.js so I can share same code with next.js and react native. But the current setup use getStaticProps for managing data fetching which makes it different.

And, is it really necessary to use SSR in every situation? I think SSR and SSG are different.

For dynamic data, especially multi-tenant SaaS. SSG just does not make sense, we don't pre-built the page with data because it might be deprecated in a sec or you never want to pre-built these pages for every client since they are all need dynamic data and constantly change, it's not that eCommerce product page kind of context which things changed in days or weeks, thinking of jira backlog, where things changed constantly.

And it will confuse the future user to think next.js does not support SSR with Apollo client anymore. (or, is it...?)

Or I miss something like:

Otherwise, moving this into its own with-apollo-ssg folder and rename the original to with-apollo-ssr seems more appropriate.

SSG is mostly just for static websites like CMS or dynamic site where data changes in a low frequency which is why people talk SSR more often, not to mention next.js works great with dynamic data as well.

Thinking of the example of a typical SaaS, there is a pattern:

Thanks

lfades commented 4 years ago

@Albert-Gao We moved all Apollo examples to SSG for the following reasons:

The examples are using SSG (getStaticProps) because it's the best data fetching method for the use cases in those examples, but it doesn't mean it won't work without it, you can still remove SSG and do client side rendering only, or add getServerSideProps / getInitialProps and it will continue to work in those cases 👍

Albert-Gao commented 4 years ago

@lfades Thanks for the quick answer. 😊

So, I think I understand the SSG right.

  1. The original with-apollo example does not use getInitialProps. Everything happens inside your component like a traditional SPA. When doing SSR, Apollo will walk through the tree and pre-fetching all the data for you on the server-side. All next.js API is easy and intuitive to pick up, but the original approach simply has 0 overhead when compares to a traditional SPA
  2. If I understand it right. You are talking about incremental building, which will make each change happens much faster than a full build. This is great. But still, like in a multi-tenant case, is it necessary to pre-generate every page for every client. Does it scale? Or I miss something? What happened to a jira-backlog like page for every tenant, will this single page get generated over and over when being requested from a different tenant?
  3. The original example demonstrates the setup with apollo ssr package which takes some setup to get there and even takes more time to combine it with cookies for authentication. So an example that works is essential, at least I think so.

Just my 2 cents. 😄

lfades commented 4 years ago

@Albert-Gao

  1. The original with-apollo example did use getInitialProps, it only allowed between getInitialProps using getDataFromTree (which is not good), or no SSR at all.
  2. Revalidation only happens once, so even if you have it set to 1 second and you receive 10.000 requests to the same page, revalidation will only happen once every second, and in the background.
  3. The apollo ssr package is not needed anymore, it was only needed for getDataFromTree, the new example still enables SSG, SSR, and client side rendering. The setup is also much simpler than before as there is less boilerplate. When it comes to authentication it's definitely possible too, although for pages that require authentication we always recommend client side rendering instead, using cookies if possible.
Albert-Gao commented 4 years ago

Thanks for the clarification. @lfades

Sorry for the misleading. I meant the original example only doing a getInitialProps at the top level but not at the page level or component level, and it only does getInitialProps if you enable ssr mode.

But your answer makes me think I might misunderstand something here. So, sorry for the noob question, let's say in a typical SaaS case, there is a page, and for each client, the page needs different data.

My question is:

In this case, isn't getInitialProps faster than getStaticProps in terms of the performance?

because getInitialProps just generates things on the fly, which is how SSR works without physically generates something that will be invalidated for a different tenant.

Thanks 😄

lfades commented 4 years ago

@Albert-Gao

In this case, isn't getInitialProps faster than getStaticProps in terms of the performance?

TL;DR: Never.

If a page uses data based on the user, you should do client side rendering with loading states, the typical case is for the page to be pretty much the same, but the data is different, so you output static HTML for the layout, and then make a request and show the data once it's ready. This is usually how pages like Twitter, vercel.com and more do it. It's better to show the client something very fast, and then make a request and let them wait with content (even if it's a loding spinner), that to make then wait in a blank page for a serverless function to return the initial HTML.

With SSG and without getInitialProps / getServerSideProps you always get static content, you never have to wait for something to "generate things on the fly" because it's already generated.

I hope that answers your question, if it's still not clear, go to our Discussions tab, there are multiple conversations about this 👍

Albert-Gao commented 4 years ago

Thanks so much for the clarification!

so you output static HTML for the layout, and then make a request and show the data once it's ready. This is usually how pages like Twitter, vercel.com and more do it.

I will check the discussion tab!

armouti commented 4 years ago

@lfades Thanks for your explanation. Just to clarify, does that mean with ssg you can load initial HTML (a loading skeleton for example) and then run it on the client like an SPA where you populate data with something like useSWR ? Or are the content of an ssg page fixed ?

balazsorban44 commented 2 years ago

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.