In this article by Kamil Przeorski, the author of the book Mastering Full Stack React Web Development introduces Universal JavaScript or isomorphic JavaScript features that we are going to implement in thisarticle. To be more exact: we will develop our app the way that we will render the app's pages both on server and client side. It's different to Angular1 or Backbone single-page apps which are mainly rendered on the client side. Our approach is more complicated in technological terms as you need to deploy your full-stack skills which working on a server side rendering, but on the other-side having this experience will make you more desirable programmer so you can advance your career to the next level—you will be able to charge more for your skills on the market.
(For more resources related to this topic, see here.)
The server-side rendering is very useful feature in text's content (like news portals) related startups/companies because it helps to be better indexed by different search engines. It's an essential feature for any news and content heavy websites, because it helps grow them organic traffic.
In this article, we will also run our app with server-side rendering. Second segment of companies where server-side rendering may be very useful are entertainment one where users have less patience and they can close the www's browser if a webpage is loading slowly. In general, all B2C (consumer facing) apps shall use server-side rendering to improve its experience with the masses of people who are visiting their websites.
Our focus for article will include the following:
Are you ready? Our first step is to mock the database's response on the backend (we will create a real DB query after whole server-side rendering will work correctly on the mocked data).
First of all, we will mock our database response on the backend in order to get prepared to go into server-side rendering directly.
$ [[you are in the server directory of your project]]
$ touch fetchServerSide.js
The fetchServerSide.js file will consist of all functions that will fetch data from our database in order to make the server side works.As was mentioned earlier we will mock it for the meanwhile with following code in fetchServerSide.js:
export default () => {
return {
'article': {
'0': {
'articleTitle': 'SERVER-SIDE Lorem ipsum - article one',
'articleContent':'SERVER-SIDE Here goes the content of the
article'
},
'1': {
'articleTitle':'SERVER-SIDE Lorem ipsum - article two',
'articleContent':'SERVER-SIDE Sky is the limit, the
content goes here.'
}
}
}
}
The goal of making this mocked object once again, is that we will be able to see if our server-side rendering works correctly after implementation because as you probably have already spotted that we have added this SERVER-SIDE in the beginning of each title and content—so it will help us to learn that our app is getting the data from server-side rendering. Later this function will be replaced with a query to MongoDB.
Next thing that will help us implement the server-side rendering is to make a handleServerSideRender function that will be triggered each time a request hits the server.
In order to make the handleServerSideRender trigger every time the frontend calls our backend we need to use the Express middleware using app.use. So far we were using some external libraries like:
Now, we will write our own small's middleware function that behaves similar way to the cors or bodyParser (the external libs that are also middlewares).
Before doing so, let's import our dependencies that are required in React's server-side rendering (server/server.js):
import React from 'react';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import {renderToStaticMarkup} from 'react-dom/server';
import ReactRouter from 'react-router';
import {RoutingContext, match} from 'react-router';
import * as hist from 'history';
import rootReducer from '../src/reducers';
import reactRoutes from '../src/routes';
import fetchServerSide from './fetchServerSide';
After adding all those imports of the server/server.js, the file will be looking as following:
import http from 'http';
import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import falcor from 'falcor';
import falcorExpress from 'falcor-express';
import falcorRouter from 'falcor-router';
import routes from './routes.js';
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { renderToStaticMarkup } from 'react-dom/server'
import ReactRouter from 'react-router';
import { RoutingContext, match } from 'react-router';
import * as hist from 'history';
import rootReducer from '../src/reducers';
import reactRoutes from '../src/routes';
import fetchServerSide from './fetchServerSide';
Important is to import history in the given way as in the example import * as hist from 'history'. The RoutingContext, match is the way of using React-Router on the server side. The renderToStaticMarkup function is going to generate for us a HTML markup on serverside.
After we have added those new imports then under falcor's middleware setup:
// this already exists in your codebase
app.use('/model.json', falcorExpress.dataSourceRoute((req, res) =>
{
return new falcorRouter(routes); // this alrady exsits in your
codebase
}));
Under themodel.jsonfile's code, please add the following:
let handleServerSideRender = (req, res) =>
{
return;
};
let renderFullHtml = (html, initialState) =>
{
return;
};
app.use(handleServerSideRender);
The app.use(handleServerSideRender) is fired each time the server side receives a request from a client's application. Then we have prepared empty functions that we will use:
We have done the basic server-side rendering in this article.
Further resources on this subject: