Deploy SPAs and programmatically manage traffic with Cloudflare Workers

TL;DR; Checkout Cloudflare Workers for deploying Single Page Applications (SPA) or handling your traffic programmatically.

Last week we talked about how we deploy our backend services on GCP. This week we'll talk about frontend deployment and traffic handling. For this we will use Cloudflare workers.

Cloudflare Workers are a serverless environment allowing you to deploy JS or WebAssembly logic to Cloudflare's edge endpoints across the world.

Not only does this allow you to easily distribute your SPA but you will also benefit from Cloudflare's anti-DdoS features and be able to manage your traffic programmatically.

For this article we will assume the following:

  • Your app is hosted under https://app.mydomain.com
  • The app.mydomain.com DNS is already pointing to Cloudflare
  • Your API backend is hosted on a PaaS at xyz-us.saas.net
  • The SPA and the API must share the same domain for cookie sharing reasons
  • Traffic going to https://app.mydomain.com/api/* must go to your backend API
  • Traffic going to https://app.mydomain.com/auth/* must go to your backend API
  • Traffic going to https://app.mydomain.com/* must go to your SPA

With the requirements above you will need two things:

  1. The ability to compile and deploy your SPA
  2. The ability to route traffic going to https://app.mydomain.com to the SPA or the API backend based on path matching.

Prerequisite

For this tutorial you will need npm setup on your machine as well as wrangler.

Wrangler's is Cloudflare's CLI for Cloudflare Workers. You can install it by running:

Introduction to Cloudflare Workers

Cloudflare Workers are a JS/WebAssembly serverless runtime allowing you to run any kind of HTTP-based application. Workers pushed to Cloudflare get deployed to all edge locations (100+ across the world).

The most minimal application looks like this:

A minimal Cloudflare Worker

You do not need to write code directly on the Cloudflare console to deploy applications. You can actually compile any JS app and push it to Cloudflare workers using the wrangler CLI.

If you wish to learn more about the Cloudflare Worker's runtime API, feel free to have a look at their doc. We will be using some of their runtime API in the second part of this article (the router).

If you wish to explore building workers, feel free to have a look at their starter apps.

Deploying your (React) SPA

Using wrangler, this is fairly straightforward.

Note that I use React as an example because this is what we use at Keypup. But any JS application can be deployed using the steps below.

Go to your React app folder and initialize a Cloudflare Worker project for your app:

This step will generate two assets:

  • A workers-site folder with bootstrap worker code to invoke your app
  • A wrangler.toml file to configure the settings of your app worker

Update the wrangler.toml file to reflect your Cloudflare configuration. Only fill the name and account_id for now.

Once you are done just build and deploy your app:

That's it! Your React app is now available at https://my-app.my-worker-domain.workers.dev

Routing traffic

When it comes to routing traffic to your SPA and your backend there are two options:

  1. Leverage the native routing of Cloudflare (DNS + Worker routing)
  2. Build our own router using another Cloudflare Worker.

We prefer to use option (2) because it gives us more flexibility in terms of programmatically controlling routing rules but I will still show you what option (1) looks like for completeness purpose.

Option 1: DNS and worker routing

The simplest approach for SPA + backend routing is using the native routing functionalities provided by Cloudflare DNS and Workers.

First we configure Cloudflare DNS to point app.mydomain.com to xyz-us.saas.net (our backend API). As such it will forward all traffic to your backend. This is not what we want just now but it will act as a default and will allow us to configure bypass routes when we are done with  the worker routing part.

Now update the wrangler.toml file and specify that your SPA should receive all traffic:

Re-deploy your application using wrangler:

All traffic to app.mydomain.com is now forwarded to your SPA.

Now let's configure bypass rules so that /api and /auth traffic is actually routed to the original DNS (the backend).

Go to the Cloudflare Workers page and add two routes to bypass Workers for /api/* and /auth/*. Ensure the Worker dropdown is set to None.

Bypass rule for /api
Bypass rule for /auth

That's it! Your app is now configured to send all traffic to your Cloudflare-hosted SPA except for the /api and /auth endpoints which are pointing to the original DNS (your backend)

It's a bit counterintuitive to setup two default routes followed by exclusion rules, but it's the only way - as far as I know - to ensure wildcard traffic gets routed to the SPA eventually.

Now let's explore the other alternative: building a custom router.

Option 2: Custom routing using a Worker

In this section, we will leave your SPA on the Cloudflare dev domain and ask Cloudflare to direct all traffic to a routing Worker which will then decide where traffic should be forwarded.

If you have modified the wrangler.toml file of your SPA in the previous section, make sure to reset it to the dev version:

Deploying your router

Use wrangler to create a new worker project:

Replace the index.js of the project with the following logic. The logic below tells the router to proxy traffic to /api and /auth to our backend API and all other traffic to our SPA:

Update the wrangler.toml of the project to tell Cloudflare that all traffic to app.mydomain.com should be handled by your router:

Now publish your newly created router using wrangler:

That's it! Your traffic is now programmatically routed to your SPA and backend API by the app router.

Testing locally

It is possible to test your routing rules locally using wrangler in development mode.

Use the following command:

Then visit http://localhost:8787 to test your logic locally and ensure traffic is routed as expected.

Note:  Cloudflare headers are not present when testing locally. If your routing logic relies on these you'll need to add them manually in you local requests (using curl or Postman).

Going beyond simple routing

You are now in full control of the routing logic to your application. This means you can:

  • Manage multiple domains (just add domains to the routes array in your wrangler.toml)
  • Stitch multiple backend services together under the same domain
  • Route traffic based on IP addresses or source country
  • Inject custom headers in the requests
  • ...and more!

Here is an example of doing country-specific routing for your backend API:

I recommend you look at the Cloudflare Worker examples to get a feel of what you can achieve.

Wrapping up

Cloudflare Workers allow you to not only deploy your SPA(s) but also take control of your whole application facade.

Their serverless approach combined with the fact that workers are deployed on their worldwide-distributed edge endpoints make it a very efficient way to manage entrypoint traffic as a whole.

If you find yourself constrained by your current traffic management capabilities I recommend you give Cloudflare Workers a try.

About us

Keypup is on a mission to help developers and tech leads work better with each others on development projects. Our platform automatically centralizes, prioritizes and assigns people and actions on issues and pull requests to optimize your development flow.

Don't get lost because you have to juggle with twenty pull requests across five development projects. We'll clean and organize that for you to ensure a smooth landing.

---

Code snippets hosted with ❤ by GitHub

Don't miss these stories: