Serverless Server-side Rendering with Redux-Saga

Michiel Westerbeek
5 min readDec 10, 2016

--

Introduction

In this post I will talk about server-side-rendering with AWS Lambda and Redux-Saga. This provides a way to pre-fetch data and put it in your initial state for your redux application. This technique allows you to quicker render your application in an “almost-final” state, without having your Javascript loaded already. This will speed up the initial load of your page.

AWS Lambda

What if you didn’t have to pay a fixed amount every month to keep your servers running, but could pay for each request that your web-app receives? That’s the gist of serverless applications. You provide the source code, and the hosting provider automatically provides your application with the hardware it requires. Amazon Web Services (AWS) is one of the providers of these kind of services, they call it AWS Lambda. Lambda is able to execute a function in Node or Python.

Recently AWS released a framework for using express web server with Lambda called aws-serverless-express. This framework allows you to run a express web server without having to run your own server. Requests are passed from AWS API Gateway to AWS Lambda, handled by your express web server, and then passed back to the client.

You can calculate the costs of the AWS Lambda setup here. Nice to mention: like most of the AWS services, Lambda comes with a free tier.

React SSR

In the React community server-side rendering has also been gaining a lot of popularity the last year(s). This allows you to pre-render your React application before you return it to the client. That way the client will see most of the final layout before the javascript is loaded in the browser. This is also really useful for SEO, because Google Bot still can’t handle javascript that well (although it’s getting better!).

Server side rendering also provides you with the ability to pre-fill the global state of your Redux application. A lot of web applications will make several API-calls directly after the javascript is loaded. This could be user-information, data that you want to display (like products in a webshop) or something else. The downside of starting these calls after the javascript is loaded is the time it takes your web application to finish rendering everything. You’re wasting precious seconds because your application wasn’t already “finished” loading when the javascript kicked in.

To solve this problem, server-side rendering allows you to provide an “initial state” to your application. Redux picks up this state and sees that the data you normally would request after initial render is already there, so it doesn’t have to fetch it anymore.

Redux-Saga

There are multiple ways to achieve pre-filling the redux store. You could do it yourself by filling the initial state object, or you could use plugins.
In my application I use Redux-Saga to deal with asynchronous side-effects of the application, for example ajax-calls. I fire a “request-action” to my redux store to fetch data. Redux-Saga receives this action, makes the ajax-call, and, when done, fires a new “success-action”.
This success-action is received by your reducers and fills the store with the received data. Your containers react to this state-change and will re-render with the right data.
You can learn more about redux-saga here.

BLRPLT

tldr: demo here.

Now, we can combine all these libraries and tricks to create a serverless express webserver. This server uses redux-saga to pre-fetch all api calls that execute on the first render of your redux application, and pass the resulting data in the initial state that gets passed back to the client!

I created a small boilerplate for this behavior that I will explain briefly in this post. The boilerplate has two start-points; client.jsx and server.jsx.

The client.jsx is the script that takes the pre-rendered HTML and pre-filled state and starts your javascript application in the browser. You can deploy this client separately to a CDN to make for fast delivery times. In traditional applications, this would be the only script you have. You wait for it to download and then it would render your entire application. But not anymore!

Because now we also have server.jsx.
The server script takes care of rendering the application (just like client.jsx) but on the server. It will actually do two renders of your application. The first time it triggers all the redux-saga actions that fire on first render. Then it waits for these actions to finish and re-renders the app with the data that redux-saga fetched in the initial data object. The result of this render will be passed back to the client, ready for client.jsx to be used.

In my example boilerplate I have a movies-request that will fetch movies from a json file. In the container that displays these movies I call the moviesRequest in the constructor. As seen in this example:

// client/containers/Movies.jsx
constructor(props: Props) {
super(props);
if (!props.movies.length) {
props.moviesRequest();
}
}

When the container is rendered, an action is fired that will be caught by redux-saga. The movies-saga will make a call for the json and fill the store with the movies. The next time this container is rendered, the movies will already be filled. That way it can render the movies without doing a new request. This is essentially how the server does the pre-rendering with data; it renders twice, first to start the actions and second to show the data.

// server/server.jsx
// When first render is done and all saga's are run, render again with updated store.
store.runSaga(rootSaga).done.then(() => {
const markup = renderToString(rootComp);
const html = renderHTML(markup, store);
const result = context.getResult();
res.status(200).send(html);
});
// Do first render, starts initial actions.
renderToString(rootComp);
// When the first render is finished, send the END action to redux-saga.
store.close();

You can read more about the Redux-Saga END action here.

You can see a demo here. (be sure to look at the page source)

I hope I have sparked your interest in serverless web applications and pre-fetching data with redux-saga. I think we will see more solutions like this in the upcoming years that makes good use of server-side-rendering.

If you find related techniques or articles please let me know!
Feel free to comment and let me know if you have any questions.

--

--