July 03, 2024



Astro and Cloudflare

I’ve found my go-to stack for simple websites, Astro and Cloudflare.

Astro caught my attention a while back with quick load times and two novel features, JavaScript islands and the ability to use multiple frontend frameworks in a single project.

The idea of the islands architecture is to treat a webpage as a sea of static HTML with a few interactive blocks. By default Astro strips out any client-side JavaScript and just renders HTML and CSS. If you want to include it, you need to be explicit. Astro’s client directives provide a few options. For components where immediate interactivity is imperative there’s client:load, and for those lower down on the page that aren't needed until the user scrolls further, we have client:visible.

Islands are Astro’s secret sauce — the reason behind its load times and why it allows any number of frameworks under one roof. Sending static HTML is fast, and the islands are isolated and free to use React, Vue, or whatever else. Beyond this Astro also brings features that have become table stakes, like file-based routing and server actions, and nice-to-haves, like easy ways to import and work with static assets like JSON. And behind the scenes it includes clever optimizations that require little work or no from the developer. When multiple components on a page use the same framework, Astro knows to only send the framework code once. And the Astro Image component converts assets to a more efficient format, webp, enforces alt text, and automatically sets height and width to minimize Cumulative Layout Shift (CLS), a web metric that measures how much items on a page move around while loading.

All of the above is great, but for me the CLI is the star. Its what makes development and deployment delightful. Adding Tailwind was as easy as astro add tailwind, and configuring to deploy on Cloudflare was similarly trivial. After running these commands, I connected my GitHub repo to Cloudflare, and within seconds we were live. Easiest deployment of my life. And everything was nearly perfect.

I encountered a few pitfalls related to Cloudflare Workers that I'll lay out, but before that I actually want to take a moment to gush about Workers. When I signed up for Cloudflare and launched my site, at no point did they ask for a credit card. I was surprised. VC-backed cloud providers offering a free tier to attract users is nothing new, but in my recent experience they've been less generous. For example, while Fly.io still includes free credits, now you need to add a payment method to do anything. I looked it up, and Cloudflare can do this because of how cheap its functions are.

Though most platforms use containers, Workers use V8 isolates, a technology to developed by the Google Chrome team. Runtimes like NodeJS were designed around a single user on a machine, not multiple tenants sharing a server's resources -- how services like AWS and Cloudflare work. In contrast, isolates were designed with multi-tenancy in mind -- allowing each tab to run its own, separate code on a single process.

Containerized runtime environments have a large memory footprint, and each container pays an individual runtime overhead. In contrast Cloudflare pays one shared overhead to run many scripts. You can learn more in this great article from Cloudflare, but basically Cloudflare's unit economics are better than other providers. They can run more code on the same number of machines, and they pass those savings on to you.

The downside is that many libraries depend on Node, and you’re pretty likely to bump up against an issue related to this. My website included a form that called a server action to send an email. At first I tried to use a package from my email service provider. But it depended on Node, so that didn’t work out. No worries. I installed cross-fetch (a fetch API that works across many runtime environments, including Workers) and copied the request format from my provider’s documentation.

The next issue was that Astro’s Image component optimizations didn’t work on workers because they rely on sharp, an image modification package that relies on Node. Astro had an adapter to use Cloudflare’s image service. But that meant additional setup, and it apparently doesn’t work with preview URLs. I considered Cloudinary, but again this meant more work and adding another service provider. Some search led me to Reddit, and there was my answer clear as day. “Just convert the images locally, on your own computer, before you upload them.” That’s exactly what I did. This simple, sensible approach was all the optimization needed for my small site with only a handful of images.

I’ve now built and deployed two websites with Astro. The first just used HTML, JavaScript, and Tailwind. On the second I used React in a few places to allow me to bring in a component library to make the interactive bits a little snazzier. In both cases the Astro/Cloudflare combo made development and deployment delightful and easy. I see myself going back to it often.