How to deploy a React SSR app on Google Cloud Platform

This is the sequel to Intro to React Server Side Rendering, so check that out if you haven’t already.

Let’s deploy a basic React SSR app on Google Cloud Platform (GCP).

In this article, I’ll deploy a Web Application Server, upload webpack bundles to Cloud Storage, and serve those bundles via CDN. I’m using the italicized terms as defined in this excellent article, Web Architecture 101 by Jonathan Fulton.

Let’s accomplish this in two parts.

Part 1: Build and start the app locally.

Part 2: Deploy to the cloud.

Part 1: Build and start the app locally

Here’s the big picture:

  1. Transpile client-side and server-side bundles via webpack.

How to build a React SSR app without any tooling or framework

Source: Reddit and Dilbert by Scott Adams

This is the first in (hopefully) a series of articles to document the lessons I learned building and maintaining SSR apps.

This article does not cover the pros/cons of SSR, or the pros/cons of not using tooling or frameworks (e.g., Create React App, Next.js, etc).

I fully acknowledge that manually setting up build configs is painful. There is plenty of great tooling out there to abstract away these configs, so you probably don’t even need to touch any of this stuff to build awesome apps.

But for those ready to embrace the pain…


Let’s start with the basics. We will…

Part 2: A further exploration of the Hooks, Render Props, and HOC patterns

c. 1512, Oil on canvas, Source:

In Part 1, I presented an approach to decouple the data fetching/management layer from a React component that renders some UI based on the data, which would free us from being locked into any particular data library or framework. Let’s call this Approach A.

Approach A. Custom Hook

Let’s create a custom hook — useSomeData — that returns the properties someData, loading, and error regardless of the data fetching/management logic. The following are 3 different implementations of useSomeData.

With Fetch API and component state:

With Redux:

With Apollo GraphQL:

The 3 implementations above are interchangeable without having to modify this UI…

And reduce the size of your future PRs with the Open/Closed Principle

KNOW YOUR ENEMY (image by Klara Kulikova, meme from Programming Memes)

Suppose I use an external service provider to process payments for my E-commerce app, and I need to embed some external SDK code to integrate the payment service into my app.

In this oversimplified example, let’s say the payment service is responsible for checking whether a given payment method (e.g, Apple Pay and Google Pay) is available based on the customer’s device, region, etc. While my “core” UI component PaymentOptions is responsible for rendering the available payment methods as options. Lastly, I want the flexibility of adding new payment methods in the future (for 📈💰reasons).

I can write it this…

And how I “program to an interface” with JavaScript functions

Source: Imgur

I‘m certain you have seen (or written) this common React pattern: (a) render a placeholder/ loader/spinner while some data is fetched via AJAX, then (b) re-render the component based on the data received. Let’s write a functional component leveraging the Fetch API to accomplish this.

Let’s say my app grows, and there are X components that use the same data fetching logic because… reasons. To avoid spamming the server with data requests, I decide to use Local Storage to cache the data.

OK… does that mean I need to update the data logic X times? 😬😱

Nope, let’s DRY…

What’s a JavaScript Promise? It’s when code vows to work every time.

Shoutout to Cassidy Williams 😀

Let’s create a button that will:

  • perform an expensive synchronous operation,
  • fire 2 AJAX requests, and
  • update the DOM based on the AJAX responses.

Here is the markup.

Here are the functions. Let’s also measure the duration of each operation with the Performance API, which visualizes when and how long each function executes on the Chrome DevTools Performance Timeline. (Thanks to JSONPlaceholder for the dummy endpoints.)

You’re still here? Good, here comes the interesting part: writing the onclick handler for the button. Since all the cool kids are doing it, let’s use async / await.

async function handleClick()…

Making the web accessible one (less) DIV at a time.

Source: Make a Meme

I used to think that accessibility is at best a UX improvement, and at worst “compliance work”. But as the pandemic turned into an essential service for many of our customers, I have read a good number of heartbreaking customer service tickets that revealed my biases and the unintended exclusions caused by my code. Now, I’m convinced that making the web accessible is the right thing to do.

Accessibility is a broad topic, and a subset of loftier inclusive design principles that I won’t pretend to be an expert on. …

What’s up? Oh nothing, just doing `this` and `that`.

Source: Programmer Humor

This is a spiritual sequel to this article.

Create a class with a method using Traditional function like so. Let’s call this Approach A.

// APPROACH Aclass SomeClass {
constructor() {
this.someProp = 'someValue';
someMethod() { // Traditional function

Create an instance of that class. When invoking the method on the instance, this refers to the instance. So far, it’s behaving as expected.

let instance = new SomeClass();instance.someMethod(); // logs 'someValue'

But, as soon as we assign the method to a variable and call that function variable, the method loses its context, and you…

Debugging: a classic mystery game where you are the detective, the victim, and also the murderer.

Image source: Programmer Humor

Here is an explainer of how cookies work. TLDR:

  • Browser sends HTTP request to server.
  • Server sends HTTP response with Set-Cookie: cookie=monster header, which sets the cookie in the browser.
  • Every subsequent request the browser sends to the server will have the Cookie: cookie=monster header.

I store a CSRF token in a cookie, which is used by the server to validate client-side HTTP POST requests. The server responds with a 403 if the cookie is missing in the HTTP request.

On the client-side, I have been using the cross-fetch package via the ponyfill approach.

import fetch from 'cross-fetch';fetch('/some-route', {…

My first of (hopefully) many stories where I expose how little I know about coding and share the lessons I learned (or re-learned).

Programmers in 1960s writing software to fly rocket to the moon, versus programmers in 2020s struggling with VIM text editor.
Programmers in 1960s writing software to fly rocket to the moon, versus programmers in 2020s struggling with VIM text editor.
Image source: Programmer Humor

When defining a method on an object, we presumably want this to refer to the object on which the method is defined.

const someObj = {
someProp: 'someValue',
someMethod: function() {
someObj.someMethod(); // will log 'someValue'

Since all the cool kids do it, I use destructuring assignments all over the place. However, destructuring a method from an object causes it to lose its original context. In other words, when invoking a destructured method, this no longer points to the object on which the method is defined.

const someObj = {
someProp: 'someValue',
someMethod: function() {
console.log(this.someProp); …

Suhan Wijaya 😎👉👉

Right-brained techie passionate about coding, product, UX, and fun adventures with my family. Let’s connect on

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