Beyond create-react-app: Why you might want to use Next.js or Gatsby instead

masakudamatsu

Masa Kudamatsu

Posted on November 30, 2020

Beyond create-react-app: Why you might want to use Next.js or Gatsby instead

Limitations of create-react-app

Once you start learning web development, sooner or later you'll learn React and use create-react-app to kickstart the building of your first React app. Or at least that's what CodeCademy taught me to do (in 2019). And I built my first React app, Line-height Picker, out of create-react-app.

However, I've noticed web developers often point out two limitations of create-react-app: (1) it takes time for the landing page to be rendered; and (2) search engine crawlers may fail to index the app.

In addition, what keeps bugging me while I'm building an app from create-react-app is this: (3) it doesn't show anything meaningful to the user who surfs the web with JavaScript disabled.

All these limitations stem from the reliance of create-react-app on client-side rendering (often abbreviated as CSR), where the app-hosting server sends the JavaScript code to the user's browser, which then runs the received JavaScript code to generate HTML documents.

Here's how CSR affects each of the three above-mentioned limitations of create-react-app.

1. The landing page appears slowly

With an app built with create-react-app, it takes time for the landing page to appear on the user's browser.

The Lighthouse audit result of Line-height Picker, a React app that I made out of  raw `create-react-app` endraw . It takes 3.2 seconds for the landing page to appear.
Figure 1: The Lighthouse audit result of Line-height Picker, a React app that I made out of create-react-app. It takes 3.2 seconds for the landing page to appear.

It is because, once the user's browser receives the data from the server, it needs to run the JavaScript code to generate the HTML document that the user can see. While the browser is busy working on rendering the page content, the user keeps staring at a blank page. It clearly doesn't contribute to a good user experience.

2. Search engines fail to index your web app

In addition, the search engine optimisation (SEO) can severely be compromised with CSR, as explained by Miller and Osmani (2019). Search engine crawlers may fail to run JavaScript to render your React app. So your React app is indexed as a blank page, which clearly doesn't help the user to find your React app by search.

3. JavaScript-disabled users will see nothing

The third limitation with create-react-app is that none of the "meat" of your React app will be shown if the user disables JavaScript on their browser.

Installing create-react-app will create the file called /public/index.html which contains the following code inside the body element:

  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
Enter fullscreen mode Exit fullscreen mode

The message enclosed in the noscript tags will be shown when the browser disables JavaScript (MDN Contributors 2020).

Ideally, however, the non-interactive components of your React app should be shown to the JavaScript-disabled users. This way, they will be able to see what the app is like, before deciding whether to enable JavaScript or not.

A workaround is to insert an HTML version of your React app into the noscript tags. But this approach is super tedious: whenever you revise the React code, you have to manually change the HTML code as well.

Most web developers appear to dismiss this concern as irrelevant today; even people in less developed countries use a JavaScript-enabled device to browse the web (see Lawson 2016).

However, when I read various comments to a Smashing Magazine article about surfing the web without JavaScript (Ashton 2018), I've learned that a non-negligible number of people actually disable JavaScript when they surf the web.

Let me cite a few of these comments. Matt wrote as recently as on 18 April, 2020:

"I'm … browsing the Web with [JavaScript] turned off. Things run faster. It's also good for bypassing pay walls on news articles and I don't get so many popups anymore"

Phillip Parr also wrote on 9 March, 2019:

"I regularly browse the web with JS disabled. Too many sites are using JS now 'just because', and overloading my connection / CPU time with frivolous multi-megabyte framework downloads. It's VERY easy to build a fast, efficient, valid, accessible site with no JS at all, and I absolutely implore everyone to do so. Quite a few sites are completely broken with JS disabled, despite being perceptually static when enabled."

As a percentage, these JavaScript-disabled users are a tiny minority. Deliberate Digital (2016) reports that 0.2% of the worldwide page views had JavaScript disabled during October to December 2016. That's a similar percentage to the global page views with Internet Explore 9 in August 2020 (Can I Use 2020).

But reading their own voices—rather than just the cold number of "0.2%"—makes me feel that we should not ignore them. The web content is for everybody. Access to information doesn't require personal connections with knowledgeable people. That's the beauty of the web.


Now that we understand the limitations of create-react-app - or client-side rendering (CSR) in general - the question is: how can we do better to build a React app?

Solution: Pre-rendering

The answer is pre-rendering, which may involve static generation, server-side rendering (often abbreviated as SSR), or both.

These jargons are often used without clear explanation in web dev articles. I myself was confused a lot, until I read a crystal-clear description by Vercel (2020), the official tutorial of Next.js (more on Next.js below).

Here is my own understanding of what pre-rendering is and how it solves the limitations of client-side rendering (CSR) while preserving the merits of React.

Merits of React

The whole problem stems from the fact that the server sends JavaScript code, not HTML documents, to the user's browser. React takes this approach for two reasons.

First, it ensures fast user interactions with the app. The browser doesn't need to contact with the server whenever the user clicks, taps, or drags the app's interface: all the JavaScript code for user interactions has already been downloaded and can be run on the browser.

Second, the use of JavaScript to render HTML documents makes it easier to maintain web pages thanks to the modular design of React Components.

These two merits come at a cost of the three limitations of create-react-app described above.

How pre-rendering works

Pre-rendering is a solution to overcome the limitations while keeping the two merits of React. It runs JavaScript code to generate HTML documents before sending any data to the user's browser. That's what "pre-rendering" means.

The pre-rendered HTML documents will be sent along with the JavaScript code for interactivity so that the first merit of React is preserved.

Web developers can still use JavaScript to compose HTML documents, the second merit of React.

Pre-rendering method #1: Static generation

One form of pre-rendering is static generation, the most popular tool for which has been Gatsby, a static generation framework for React-based web development. I kept hearing its name for powering "blazing fast" websites, without knowing what Gatsby was special about. Now I know why.

Static generation converts your React JavaScript code into HTML documents before you deploy your React app. This has two consequences.

First, when the user visits your web app, the server sends the pre-rendered HTML document to the user's browser. Consequently, the user will save time for rendering HTML documents by running JavaScript on their browser.

Second, even when the user disables JavaScript, he or she still sees the landing page instead of a cold message "Please enable JavaScript". So does the search engine crawler.

This is a great solution for websites such as blogs which do not involve interactive features other than hypertext links. You can use React to compose HTML documents without sacrificing the speed of rendering the landing page.

Aside from Gatsby, static generation can be implemented with Next.js since its version 9.3, released on March 10, 2020 (Neutkens et al. 2020a). Below we compare these two options for static generation in the final section of this article.

If you have already created a React app with create-react-app, refactoring the code for Gatsby or Next.js is a big headache. In this case, consider Navi, which allows you to convert the code based on create-react-app into a statically generated one.

Pre-rendering method #2: Server-side rendering (SSR)

Another form of pre-rendering is sever-side rendering (SSR), which deals with a drawback of static generation at the cost of a slower rendering speed. Di Mattia (2021) concisely explains how server-side rendering works, with nice illustrations.

Static generation cannot work with live data such as social media feed, because HTML documents were already created before deployment.

SSR can handle live data because it converts your React JavaScript code into HTML documents when the user accesses the website.

The cost of doing so, of course, is that the user needs to wait while the server runs the JavaScript code to generate HTML documents. However, unlike static generation, the latest pieces of data (e.g. social media posts) can be incorporated into the HTML documents delivered to the user.

As far as I can tell, Next.js has long been the React framework for SSR, and it still is.

Gatsby vs Next.js

For static generation, you need to decide which framework to go with, Gatsby or Next.js. Here are some pieces of information to help you make a choice.

There are a countless number of articles that compare these two React frameworks. But I advise you to ignore all of those written before March 10, 2020, because Next.js was incapable of static generation until then (Neutkens et al. 2020a).

Cases for Gatsby

In an article written one month after the release of Next.js 9.3, sidney (2020) claims "Gatsby Won Against Next.js" after he himself built the same website with both frameworks. LightHouse performance scores are slightly higher for Gatsby (78 vs 74). He also mentions that documentation is better with Gatsby.

But this is the only article that I've found is in favor of Gatsby.

Gatsby's own website provides the comparison chart between the two (Gatsby 2020). Unsurprisingly, it claims that Gatsby provides more features than Next.js, although it is unclear which version of Next.js they refer to. As Next.js keeps updating itself, most recently on Oct. 27th, 2020 (Neutkens et al. 2020b), this comparison chart may be outdated by now.

Cases for Next.js

Laing (2020), written one month later after Next.js becomes a static generation tool, argues that Next.js is a better option because of its SSR capability. Maybe you start out building a static website. But then when you realize you need SSR, Next.js just allows you to implement it while Gatsby does not. For each feature that he mentions Gatsby is better at, there is a comment to this article saying Next.js, too, has that feature.

In the Twitter sphere, Next.js appears to get more popular.

A Twitter poll by Buaiscia (2020) on July 6, 2020, shows that 7 out of 13 voted for Next.js as a blogging platform while 5 voted for Gatsby.

McDaniel (2020), tweeting on August 4, 2020, is in favour of Next.js:

"Switching this new site to #nextjs from #Gatsby. The more I started getting everything together the more I realized next js was going to be a better choice. Love me some gatsby though."

The NPM weekly download data backs up this trend:
A screenshot of NPM Trends on November 30, 2020, where the weekly number of NPM package downloads is compared between Gatsby and Next.js over the last one year.
A screenshot of NPM trends on November, 30, 2020

The popularity of Next.js is on the rise from around 400,000 to 1,000,000 downloads per week while Gatsby's is stagnated around 400,000 per week.

Of course, the number of package downloads doesn't mean the number of people who actually keep using it. But it is an indication of reputation. People won't download it unless they hear something good about the package.

Verdict

As of November 2020, Next.js appears to be more suitable for a static generation tool.

If you want to decide which to use on your own judgement, instead of relying on what people say, Smashing Magazine recently interviewed the person behind each React framework, for the audience who doesn't even know what static generation is. Listen to each's sales pitch, and decide which one you will go with.

Update on 2 August 2021: Gatsby now supports SSR with the introduction of Gatsby Functions, released in June 2021 (Gatsby 2021). See Scanlon (2021) for detail and how to use it.


This article is part of Web Dev Survey from Kyoto, a series of my blog posts on web development. It intends to simulate that the reader is invited to Kyoto, Japan, to attend a web dev conference. So the article ends with a photo of Kyoto in the current season, as if you were sightseeing after the conference was over.

So let me take you to the world's famous zen garden at Ryoan-ji Temple:
A photo of Ryoan-ji Rock Garden in autumn
Ryoan-ji Temple Rock Garden at 8:26 am on 29 November, 2019. Photographed by Masa Kudamatsu (the author of this article)


Hope you have learned something today! Happy coding!

Footnote

I use the Author-Date referencing system in this article, to refer to various articles on web development.

References

Ashton, Chris (2018) "I Used The Web For A Day With JavaScript Turned Off", Smashing Magazine, May 8, 2018.

Buaiscia, Alex (2020) "A Tweet on July 6, 2020", Twitter.

Can I Use (2020) "Browser Usage Table" caniuse.com, 8 September, 2020.

Deliberate Digital (2016) "What percentage of browsers with javascript disabled?", deliberatedigital.com.

Di Mattia, Sandrino (2021) "The Ultimate Guide to Next.js Authentication with Auth0", Auth0 Blog, Mar 3, 2021.

Gatsby (2020) "Comparison of Gatsby vs Next.js", gatsbyjs.com.

Gatsby (2021) "v3.7 Release Notes", gatsbyjs.com, June 2021.

Laing, Malcom (2020) "Which To Choose in 2020: NextJS or Gatsby?", Frontend Digest, Apr. 18, 2020.

Lawson, Nolan (2016) "Progressive enhancement isn't dead, but it smells funny", Read the Tea Leaves, Oct. 13, 2016.

McDaniel, Josh (2020) "A Tweet on August 4, 2020", Twitter.

MDN Contributors (2020) "<noscript>", MDN web docs, Apr. 12, 2020.

Miller, Jason, and Addy Osmani (2019) "Rendering on the Web", Web Fundamentals, Nov. 26, 2019.

Neutkens, Tim, Joe Haddad, JJ Kasper, Luis Alvarez, and Shu Uesugi (2020a) "Next.js 9.3", Next.js Blog, Mar. 10, 2020.

Neutkens, Tim, Joe Haddad, JJ Kasper, Connor Davis, Luis Alvarez, Shu Uesugi, Belén Curcio, and Steven (2020b) "Next.js 10", Next.js Blog, Oct. 27, 2020.

Scanlon, Paul (2021) "Gatsby Serverless Functions And The International Space Station", Smashing Magazine, Jul 26, 2021.

sidney (2020) "Gatsby Won Against Next.js in this Heads Up Competition", Hacker Noon, Apr. 27, 2020.

Vercel (2020) "Two Forms of Pre-rendering", Next.js Docs.

💖 💪 🙅 🚩
masakudamatsu
Masa Kudamatsu

Posted on November 30, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related