In the previous article we went deep into the differences between Client Side Rendering, Server Side Rendering, and Static Site Generators. We checked how both search engines and crawlers work and what to do when Client Side Rendered application is not enough. Let’s check possible solutions we have to create pre-rendered content on the server and decide if they are worth using.
Static Website in 2019
A question may arise: Do we really need generators at all? Let’s assume you need to create a static website in 2019. How can you approach it? A few years ago the development process usually started by picking up some html5 skeleton structure with reset.css applied and all the useful meta tags added. Later on we were adding grid system to build layout structure, some UI framework like bootstrap for UI components and, of course, JQuery because of a large number of ready-to-use plugins doing magic just in a few lines. Naturally, at some point, we needed to work with JS modules so we added a webpack to solve file imports and npm scripts to do some automation.
The above list of to-do things is long, and it’s not trivial to setup everything correctly. What other alternatives do we have? It’s a moment when static site generators come to play. Why not to use the ecosystem we already know to create a standard website? We can write our website in the same way we are do SPA applications but only with a few minor additions.
To be more specific: we can write application in a framework like React while using the whole ecosystem it provides with Redux and the stuff we used to work with and create static website from that.
Static Site Generators comparison
Let’s assume that we have decided to use Static Site Generator for our new website. What we need is the elements such as social sharing on Facebook and the ability to be indexed not only by Google. It would appear that a statically generated website is a perfect solution for us. The question is how to choose the correct framework which will fit our needs?
First, let’s dig a little into what the most popular solutions currently are. There is a great website which collects most ‘generator’ solutions for different languages: https://www.staticgen.com/
Probably you get the same impression as me: this list is so looong! How can I pick anything when all these frameworks are able to do the same things in similar way? How can I choose a tool to do the job? The rules that you will find below should be of some help.
First rule: choose the solution with the largest support from the community. The more stars and forks on github, the more people are involved behind the framework. It also means that if any troubleshooting comes up, there will be someone able to answer our tricky questions.
Second rule: let’s pick up the solution based on the language we know best. The majority of solutions are for: JS, Ruby, Python and Go. So there is a possibility that anyone will be able to find the solution closest to their programming background.
In the case of React, NextJS framework is even more popular than both solutions mentioned above, but it is something more than just Static Site Generator. It’s a fully working solution for Server Side Rendered applications in React with a possibility to export static site like generators do.
Static Site Generator for React – GatsbyJS
GatsbyJs is the most popular generator based on React framework. Let’s see how to build a website with it in just a few steps.
GatsbyJs comes with cli tool which is similar to the well-known react-create-app. Cli tool gives us the opportunity to start developing with zero configuration. We can easily install cli tool globally with:
npm install –global gatsby-cli
With the cli installed globally we can easily create our first application based on the already existing and prepared structures. Here we can find a list of all available gatsby starters. We can choose the suitable one depending on our needs, there are starters with Material UI or Bootstrap attached, Typescript integrated or with i18n already configured. The use of starters facilitates the initial work in order to start development. Naturally, we can create our own setup by adding libraries we need and by configuring them.
The minimal setup can be done by using the following command:
gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default
I recommend it only if you want to setup everything by yourself, to learn how to extend what gatsby provides us with by default. Adding such elements like sass support or styled-components will require installing appropriate plugins from: https://www.gatsbyjs.org/plugins/ and adding simple config entries to gatsby-config.js file. The standard libraries like Redux etc. are installed in a classical way by npm and can be imported anywhere.
Here is a starting structure we receive from a default-gatsby-starter:
We have very a basic structure, but it’s enough to create our first React application rendered by NodeJs. When you look into the catalog structure you may discover that something here is missing. There are no react-router at all. How is it possible? The answer to this question lies inside the page’s catalog. Each page is automatically transferred to a separate route in our application based on a file name. Each file under the page’s catalog will be a starting point for us to put containers connected to Redux with the nested components.
In order to check if everything works fine, we can run our application in 2 ways:
- Development mode – with changes hot replacement, in this mode the application is rendered client-side like classical React app.
- Build mode – in this mode all our pages are rendered separately on NodeJS side and pushed to public folder as html files. Each html file has its own script, style or asset generated.
Let’s build our website with the npm run build command. The effect of rendering our app in Node JS is available under the /public folder. Now, we can deploy everything there to any http hosting or to serve files from our localhost. We can use http-server for the local tests
The above command will start the local http server from the public folder where all our generated assets are present. The content of each file is provided by the server. React just attaches itself to an already generated html structure.
Gatsby JS vs React – differences
In most cases, developing with GatsbyJS is exactly the same as developing a standard React application. Although during the development process we may spot some differences:
componentDidMount – not all lifecycle hooks are executed while rendering in Node JS. This one is executed only in a browser. So, if we want to perform certain actions which will not be part of Node JS rendering, we can place it here.
window is undefined – a window object does not exist in NodeJS, if we attach something to the window object in our constructor function, the building process will fail. If we need a code which relies on the window object we should always check if window exists, or to place the window dependant code in the componentDidMount lifecycle method.
external libraries fails – some external libraries may fail if they are imported in a normal way. It may be caused due to the window object usage. The workaround will require our module inside the componentDidMount to be executed for browsers only.
pre rendering dynamic content – there may be a situation when we develop a blog website connected to headless CMS. In such a case, we need to get our posts content using AJAX to populate particular views in our application. Also, we want the fetched content to be pre-rendered for Facebook sharing or non-Google crawler indexing. We cannot simply call AJAX inside components lifecycle methods because AJAX response will not be rendered by Node. It’s a place where gatsby-node.js proves helpful. Inside the file we can use server side rendering lifecycle methods: https://www.gatsbyjs.org/docs/node-pis/. The one which will be useful most is onCreatePage, recalled each time a new page is created.
The above screen presents a way how to make AJAX response content also rendered inside Node JS. For a specific page, based on page.path we are able to get the necessary data and inject them inside the page.context object. The downloaded data will be available in our Page components under props.pathContext. Mind you, it also makes our building process longer because of the waiting time for all AJAX calls to be finished with async/await syntax.
use framework ecosystem – gatsby provides us with the helpers to improve a website development process. The one worth mentioning is Gatsby Link. It is a wrapper component for the react-router link. The standard links navigate between different pages which is the reason why there is always a delay to download a proper html file with all resources. So, why can’t we improve that process? With Gatsby link, the framework checks for us whether the link is in a current viewport and if it makes the silent prefetching content to be available faster after every click.
be careful with external libraries – some libraries may work differently in the development mode (client-side rendered) and differently after being built, when served from static html files. To show the problem let’s use a simple grid library for React: https://github.com/JSxMachina/react-grid-system
Let’s create a simple structure. Lg property means that above 992px width we will display 3 columns next to each other and below that value there will be one column with all the texts one below another.
With Develop mode everything seems to be working perfectly. The components are rendered in 3 columns above 992px and in one column below that. Everything works as expected.
Let’s check what will be the result of the building process. After making the resolution larger than 992px everything is fine. The 3 columns are displayed immediately:
You are probably wondering what will happen on the mobile resolution.
For a brief moment the content is rendered in 3 columns instead of one like in the above, and after a second the content is correctly displayed in a one-column view like below.
GatsbyJs is only one of many frameworks which perform Static Website Rendering. Recently, I have also tried React Static which, in my opinion does exactly the same thing. I can’t spot any major differences between those two, they look almost like twins.
On the other hand, there is a very popular Next JS framework also based on React with the ability not only to do Static Side Rendering like Gatsby, but also to provide a way to render our components server-side on the fly. It may prove very helpful with the dynamic data which cannot be loaded client-side or pre-rendered during the building phase. NextJS for sure deserves its own article with a detailed explanation.