Universal rendering with Preact

As @rauchg stated, server renderer pages are not optional. On my journey redoing the HackDash front-end I’m trying to apply best practices on this software piece, so implementing Universal rendering was one of the first challenges.

In this article I explain a technique and conventions to follow in order to achieve Universal rendering (the ability to render an app both client and server side) using preact, node and redux. This is not the only way to do it but it can help you understand some concepts behind this technique. You can see a demo of the Work in Progress using now for the deployment here, the code is Open-Source.

TL;DR

An easy way to develop this kind of single-page apps with universal rendering is to break your app in pages (in my case each page refer 1-on-1 with a route) and provide an initial fetch redux action for each page. Then, on the server, provide a middleware to fetch that data and when you get the redux action that indicates the data is loaded, render the page along with a JSON representation of the initial state of the app.

Transpile your server-side code (too)

Because we want to render our client-side preact app on the server, importing the client code into the server, we need to transpile our node code too. Webpack allows to specify a node target that deals for this specific environment while helping with, for example, the jsx components.

Avoid the usage of browser specific variables

Using browser-only variables like window and document will break your server builds. If you must use them you can access to global polyfills or declare them as external on your webpack configuration.

Share as much code as you can

The only difference between the code executed in the server and the client is a minimal express app. This code is in charge of fetching the initial data for the required page (using the same redux store as the front-end) and render the initial HTML document. Is important to notice the 1-on-1 mapping between the client and the server routes.

Identify each page first render data

This may be the hardest part of this technique. There should be one entry point for each page. This doesn’t mean that you can do only one request for a page, you only need to identify when the first render data is loaded and dispatch a SERVER_READY action. This will allow the middleware to know when to render your app. The way I prevent the first data to be fetched again on the client is just with a boolean indicating if the app was already mounted once.

More to come

As I said, this is just a WIP. This is the first of a serie of follow-ups on the development of the app. You can follow me on twitter as @impronunciable.

 

last updated on 2020-08-27