Backend for Frontend Developers with Cloudflare Workers

Yaron Karlinski
Lightricks Tech Blog

--

Sometimes your front-end team just needs a simple back-end service. Maybe you want to call a service with a secret API key, like OpenAI’s ChatGPT, or add a watermark to a photo.

For JavaScript experts, Node.js is often the “go to” solution — and it often ends up messy.

If you have been coding JS for long enough, or if you are adventurous enough, you’ve probably tried running a production server, and struggled with keeping the service running consistently, debugging production, and dealing with peak traffic (I’m looking at you Nodemon!).

Why do these projects lead to so many problems? Well, because it takes effort to scale into a production-quality service.

You need to consider: scaling, logging, debugging on production, security, error handling, concurrency, and clustering… so many things! In Lightricks Web Team, we have services responding to millions of requests per day, and we found the Cloudflare Workers ecosystem to be stable and easy to configure and develop against this phenomenon. I’ve never had to put so little thought into a back-end service.

In this post I will share our experience with using Workers, and hopefully by the end of it, you can take your first steps towards building your own production-grade simple back-end.

What are Cloudflare Workers?

Cloudflare Workers represent an innovative approach to serverless computing. Unlike traditional server setups where applications run on a specific server or group of servers, serverless computing is an execution model where the cloud provider dynamically manages the allocation of machine resources. The term “serverless” doesn’t mean that servers are not involved; it just means that developers do not have to think about the servers. They can just focus on the code, and the infrastructure is handled by the cloud provider.

Let’s first see a couple of basic examples of what we could do with Workers.

A/B testing
Cloudflare Workers can be used to implement a basic form of A/B testing, where you serve different versions of your webpage to different users.

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
// Fetch both variants
const variantA = fetch('https://website.com/variantA')
const variantB = fetch('https://website.com/variantB')

// Randomly (50/50) choose between variantA and variantB
const response = Math.random() < 0.5 ? variantA : variantB

return response
}

Or add a content security policy to all pages:

addEventListener('fetch', event => {
event.respondWith(addHeaders(event.request))
})

async function addHeaders(request) {
// Fetch the original request
const response = await fetch(request)

// Create a new response based on the original
const newResponse = new Response(response.body, response)

// Add the CSP header
newResponse.headers.set('Content-Security-Policy', "default-src 'self'")

return newResponse
}

Unpacking Cloudflare Workers: A Closer Look at Their Capabilities

In the realm of serverless computing, Cloudflare Workers hold a unique position. As we navigate through this discussion, we will delve into the technical aspects that make Cloudflare Workers an advantageous tool for JavaScript practitioners.

1. JavaScript Execution in the Cloud

Cloudflare Workers provide an environment for JavaScript execution in the cloud, powered by the V8 JavaScript engine — the same engine that drives Google Chrome and Node.js. The advantage here is two-fold. First, the serverless model eliminates the need to manage and maintain infrastructure, thereby reducing overhead. Second, the use of the V8 engine ensures that your JavaScript code is executed efficiently and consistently across Cloudflare’s vast network of edge locations. This significantly reduces latency, ensuring your application remains responsive, even under heavy load.

2. Route-Based Execution of JavaScript

One distinguishing feature of Cloudflare Workers is their ability to run JavaScript code at specific routes (URLs). This attribute facilitates precision in how requests are handled. Cloudflare Workers employ an integrated routing mechanism, enabling you to specify which routes or URLs should trigger the execution of your Worker script. This becomes a powerful tool, as you can control how requests are processed and responses are generated at a granular level — from determining specific responses for individual paths to routing requests based on HTTP methods, headers, or cookies.

3. Integration with npm packages and TypeScript

From a development perspective, the fact that Cloudflare Workers support npm packages extends their versatility significantly. With this feature, developers can leverage an extensive range of packages available on npm, thereby reducing the need to reinvent the wheel for common tasks or complex operations. There is one major caveat here: while npm packages designed for the browser work well, those written for Node.js might face difficulties, since concepts like the filesystem make no sense in the scope of a serverless Worker.

Cloudflare Worker Use Case : Dynamic Sitemap Generator

Sitemaps are a crucial part of any website’s SEO strategy, enabling search engine bots to effectively crawl and index the website’s content. Yet, maintaining a sitemap can be a daunting task, especially for large or dynamically changing websites. This is where Cloudflare Workers shine.

Consider the case where you want a Worker to automatically generate and serve your sitemap based on the actual state of your pages. You might want to ignore pages returning 404 errors or those tagged with noindex. You might also want to respect the robots.txt rules while generating the sitemap. This can be easily achieved by creating a Worker that runs periodically (using Cron Triggers) and another one that serves the sitemap to bots.

Here’s a simplified code snippet on how you can utilize Cloudflare Workers for generating and serving a sitemap. This code imports a couple of npm packages (cheerio and robots-parser) to help with parsing HTML and robots.txt files.

import cheerio from "cheerio";
import RobotsParser from "robots-parser";

async function generateSitemap() {
// Fetch your website's pages
const pagesResponse = await fetch("https://www.yoursite.com/pages");
const pages = await pagesResponse.json();

// Filter out pages based on status codes or `noindex` tags
const validPages = pages.filter(page => {
// You can add more sophisticated checks here
return page.status !== 404 && !page.noindex;
});

// Download and parse robots.txt
const robotsTxt = await fetch(`https://www.yoursite.com/robots.txt`).
then(r => r.text());
const robots = RobotsParser(`https://www.yoursite.com/robots.txt`, robotsTxt);

// Create sitemap based on valid pages and robots.txt
const sitemap = validPages
.filter(({ url }) => robots.isAllowed(url, '*')) // Check robots.txt rules
.map(({ url }) => `<url><loc>${url}</loc></url>`)
.join('\n');

// Save sitemap to Cloudflare's key-value store (KV)
await MY_SITEMAP_KV.put("sitemap",
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${sitemap}
</urlset>`
);
}

// Use a Cron Trigger to run the sitemap generator every day
addEventListener("scheduled", event => {
event.waitUntil(generateSitemap());
});

// Worker to serve the sitemap
async function handleRequest() {
const sitemap = await MY_SITEMAP_KV.get("sitemap");
return new Response(sitemap, {
headers: { "Content-Type": "application/xml" },
});
}

addEventListener("fetch", event => {
event.respondWith(handleRequest());
});

This is a simplified example, but it gives a general idea of how Cloudflare Workers can be used to automate an essential SEO task. By combining the power of Cloudflare’s edge computing with the flexibility of JavaScript and npm packages, we can simplify tasks that traditionally require more complex back-end logic.

In this case, we are making use of several Cloudflare capabilities:

  • Cron Triggers to periodically run the Worker for generating the sitemap.
  • Key-Value Storage for persisting the generated sitemap so it can be served later.
  • KV storage is an an extremely quick type of database, like redis or memcached. Cloudflare stores the data on several locations and keeps all sources synced.
  • Fetch API for fetching the website’s pages and the robots.txt file.
  • Event Listeners for both scheduled tasks and request handling.
  • Importing npm packages, cheerio, and robots-parser, which make HTML and robots.txt parsing easier. In Cloudflare Workers, we can seamlessly use npm packages using standard JavaScript import syntax, as demonstrated in the code.

By utilizing these capabilities, Cloudflare Workers provide a powerful platform for frontend developers to take on backend responsibilities efficiently.

The Power of Wrangler: Development, Deployment, and Debugging with Cloudflare Workers

When using Cloudflare Workers, you’re not just getting a powerful platform for serverless JavaScript, but also a suite of excellent developer tools bundled with Wrangler: Cloudflare’s CLI for managing and publishing your Workers.

Let’s look at a few of the crucial aspects where Wrangler shines:

Development and Deployment

Wrangler makes development smooth with its configuration file `wrangler.toml`. This file allows you to specify your project details, such as account ID, routes, and other environment variables. Here’s a basic example:

name = "my-worker"
type = "javascript"

account_id = "123456789abcdef"
workers_dev = true
route = ""
zone_id = ""

[build]
command = "npm install && npm run build"

[build.upload]
format = "service-worker"

This makes deploying your Worker as simple as running:

wrangler publish # Run this in the command line

Debugging in Production

Debugging in production can often be a tricky business, but with Wrangler, it’s incredibly straightforward. Using `wrangler tail`, you can get real-time logs from your Worker. This is perfect for debugging and identifying any issues happening in production.

```bash

wrangler tail — format=pretty

```

This command streams the logs from your Worker as requests are coming in. The ` — format=pretty` flag will output your logs in a readable format, making it easier to spot any errors or anomalies.

Wrangler’s Dev Server

One of the shining features of Wrangler is the local development environment it provides. By running `wrangler dev`, you can start a local server which simulates the Cloudflare Worker runtime. This allows for rapid development and testing of your Worker code in a local environment.

```bash

wrangler dev

```

This powerful set of tools and features, combined with the simplicity of JavaScript, truly elevates the backend development process. With Wrangler and Cloudflare Workers, you’re well-equipped to handle the challenges of modern web development and ready to bring your innovative ideas to life!

Conclusion: Why Trust Our Insights?

This entire exploration into the world of Cloudflare Workers comes from our direct experience at Lightricks, a tech unicorn that sees an enormous amount of traffic on a daily basis. We’ve been where you are: dealing with complicated backends, wrestling with production-level challenges, and trying to balance it all with the demands of fast-paced front-end development.

We chose Cloudflare Workers for many of our production apps due to their scalability, ease of use, and robust ecosystem. We’ve seen firsthand how they can simplify the development process, and we believe in sharing these insights so other developers can also benefit.

In a world where frontend development is becoming increasingly complex, Cloudflare Workers offer a compelling way to handle backend functionalities with the same level of simplicity and elegance that JavaScript developers are familiar with. Whether it’s creating dynamic sitemaps or setting up a reverse proxy, the possibilities are endless.

At Lightricks, we’ve learned to appreciate the power of Cloudflare Workers, and through this blog post, we hope to share that appreciation with you. By leveraging Workers, you can potentially save time, avoid common pitfalls, and focus on what truly matters — building fantastic user experiences.

--

--