Divar-starter-kit: How do we do SSR in Divar.ir

Divar-starter-kit

Divar-starter-kit is a React.js SSR-ready boilerplate using Razzle by Divar. It also contains tool-chains for quest start and offers file-structures that we often use to develop our front-end projects. The project mainly focused on Server-Side-Rendering but also helps you to have a quick-start and directly jump to developing.

Features:

  • React and Razzle features.
  • Next.js like SSR features without file system routing.
  • Redux ready (CSR and SSR).
  • Using React-router-config.
  • Recommended Directory Layout.
  • HTTP service included (using Axios).
git clone https://github.com/divar-ir/divar-starter-kit.git
cd divar-starter-kit
yarn
yarn start

Divar website from past to present

Divar (means wall in Farsi/Persian) is the largest horizontal classifieds in Iran with over 35 million users and more than 500 thousand daily ads. Many of our users use web application and creating a great user experience always is one of our goals.

Why Server Side Rendering is important for web businesses?

Divar web client was a Single-Page-Application (after migrating from the first version — server template rendering with Django). Using SPAs create a grateful UX and DX in most cases but any improvements come with expenses.

  1. Pre-Rendering / Static Site Generating: build your all pages as static HTML files and serve. You can deploy them on a CDN and have a great site speed without any server costs. It's a great approach for low refresh rate content websites (like news sites — about 10 builds a day for each post). Not a good option for Divar.ir — about 10-15 new posts posted in every second).
  2. Server-Side Rendering: Request data and render the page that the user wants on the first website request in server. Users and crawlers see meaningful content while the bundle is downloading and mounting.

Our “previous” approach for doing SSR

We first did SSR in React without any external tool for THE-WALL (web client internal code name) many years ago.

Problems with the “previous” approach

  • First, having various methods for SSR (async and sync) for doing SSR added uneccessery complexity to views. It also couples views to SSR implementation.
  • Second, if a view needs SSR, we should use store to manage loading state and prevent repeating data fetching. However, the use of store has its own logic and reasons. In addition to unrelated use of store for our case, it added a bunch of code like reducers, actions, action-types, and registering reducer and connecting to store.

Revision to SSR approch

In 2019 and in order to start developing our new brand site: karnameh.com, we did research and review on our SSR approach.

  • Typical server-side rendering.
  • No structural and technical limitations and the possibility of using different libraries (especially react-router)
  • Ability to use Redux in server-side and client-side.
  • Access server-side data in client-side without using store.
  • A better developer experience.
  • Next.js: This framework seemed to be a good option due to good development and support, large community, and easy and fast startup, but the impossibility of creating nested routes caused the components to repeat. Also, its routing system is opinionated, which imposes serious restrictions on the project structure and technical cost of migration from the current routing structure (react-router-config).
  • After.js: The use of this framework was close to our technical and product needs, but the lack of proper nesting routing at that time and of course, the lack of maintenance were the main reasons for not choosing this option.
  • Final Result — Implementing SSR by ourselves:
    Once again, considering the needs of the products and the fact that we intended to keep the platform of front-end projects same and help reduce technical costs and easy transfer between projects, we decided to develop SSR ourselves once again and upgrade the codebase to make exactly what we need. We knew that using previous SSR development experience reduces technical and time costs. Of course, we also got help from Razzle.

Using divar-starter-kit

In general, to use existing experiences and prevent duplication, we set the starting point based on the method in the THE-WALL project. The difference is that in addition to adding features such as Hot Module Replacement to the server-side during development, it reduced a significant amount of code and complexity associated with webpack configurations and development tools due to the use of Razzle. While the capabilities of the previous method (specifically sending redux store data from server to client) were still supported.

Example of how to use the serverSideInitial method
How to get values from SSR with withSSRData HOC

Divar-starter-kit in depth

We used a react-context to store the received data from the serverSideInitial functions, which uses in server-side and client-side as provider and in withSSRData as consumer.

  • A data property that contains all the data related to serverSideInitial (with the structure described below).
  • A function called clearDataByKey is used to clear data for a view after use.
  • ServerSideInitial method of each view
  • Determine whether is a view requires the returned data of that method. Detection of this point is done by checking if the view wrapped inside withSSRData HOC.
  • Path related to the view. Which will then be used as the unique data storage key of that view.
Usage of context in initial render. src / server / handlers / ssr-handler.js

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store