This repo is a research project with a goal to create a production-ready prototype of the React App with the Server Side Rendering.
Motivation
Many SSR examples exist already. The problem is they are either too simple and show only the small part of the picture, or too complex to understand all the reasons behind the technical decisions were made. In this repo, I'm going to create a production-ready prototype and cover the most often web app requirements, like routing, state management, CRUD, SSR, performance. But do it gradually, solving one problem at the time and making a snapshot on each step. If your goal is to understand deeply every concepts/pattern/hack under the app with SSR, you may find this repo useful.
When a prototype is complete, I would love to create a video tutorial, where I recreate it one more time together with watchers, line by line. Set the thumb up for this issue if you want to see such tutorial.
How to run examples
Move to the folder with an example, for example:
$ cd 01/
Install libraries:
$ npm i
Start server in console #1:
$ npm run start-server
Run webpack-watch in console #2:
$ npm run webpack-watch
The first example has the basic (far away from the production-ready) React App with SSR.
Data fetching challenge should be solved on this step. There are two possible architectured solutions: fetching data on the endpoint level or on the component level.
Before the "FE app" era, the first approach was widely used. Developers thought about a site as about a set of pages: endpoints fetch all the data first and render it after. Nowadays, an app is rather a set of modules/components and co-locating the data fetching inside them, from my experience, is the way that shows itself as more effective.
If you prefer fetching the data on the endpoint level, neither from the two problems described below should appear.
The flow:
- user requests a page
- server starts rendering a React application
- components are rendered the first time without waiting for the promise that should return data
- server doesn't wait for those promises either and returns a response without data
ReactJS Team hasn't given an answer yet. This issue was reported in 2014 and discussion is ongoing.
As per my opinion, component should have an ability to return a promise, which will be ignored in the rendering until resolving.
Option # 1 – Skip the first render
This works exactly how it sounds. In the example#01 I use react-frontload that takes care of it.
Do you know other options? Let me know!
This problem is very similar to the previous, but just from the Frontend perspective.
The flow:
- user requests a page
- server returns an HTML (with all data)
- browser renders the page
- user sees the resulting page (screenshot #1)
- React is initiated and it renders components into DOM
- components start loading data
- while data is loading user sees a blank page or loading wheel (screenshot #2)
- components render loaded data
- page looks the same as before the initialization of React (screenshot #3)
This is how it can look like for a user:
#1 | #2 | #3 |
---|---|---|
|
The same as for Backend: component should support the Promise protocol.
Option # 1 – Leave it without solving the problem
Pros:
- SEO friendly site without additional layer of code to solve the data blinking problem
Cons:
- despite a page with all data is available in the first response from the server, user should wait until it's loaded the second time from the FE app
- performance is worth than in the architecture without SSR, because the code to generate data is executed twice: the first time in SSR, the second time in AJAX requests to prepare the same data
- user will see data blinking, as on the screenshots
It's possible to avoid data blinking by hiding the content until components render it one more time. Nevertheless, the DRY rule is breaking up in a very harsh way here.
Option #2 – Pass an initial state from the server
SSR could pass data for the required endpoint in the HTML response,
for instance, in the window
object.
Pros:
- no additional request for the initial data in FE app
- performance is not affected as in option #1
- blinking problem is solved: components have all data in the first render (technically re-render happens, but because the initial HTML and result of the render are identical, a user won't see any changes on the screen)
Cons:
- a response from server has data duplication: already rendered and in some
window.store
object
Do you know other options? Let me know!
The last approach is used in the example#01.