When 🎏Glitch shut down hosting, I moved Froggy Chore to be hosted on Render, which was one of the recommendations from Glitch staff. I'm not a huge fan of their stance on LLMs, but in terms of a web app host they've been pretty easy to use. Their pricing is a bit expensive for a single project if you don't want their free tier, but I eventually plan to run several backend apps on Render so the monthly base charge will even out eventually.
The main inefficiency cost-wise of Froggy Chore is that it has no caching. On Glitch, static assets were uploaded directly to a CDN and you referenced them directly in your code, but Render only serves whatever your backend responds with. I had planned to put a CDN on top of it eventually, but Render recently shipped edge caching for web services, which makes the task much easier.
Before turning on edge caching, I needed to make Froggy Chore's backend start adding Cache-Control
headers to responses to signify whether they should be cached or not. For Froggy Chore, there's three types of requests:
Any request to /assets/*
is requesting a Vite-processed asset like the site's JavaScript, CSS, or images. These have hashes in their filenames based on their content, so we can cache them aggressively for a year with Cache-Control: public, max-age=31536000
.
These are what fetch and modify the contents of your chore list. These cannot be cached and should probably have Cache-Control: no-cache
, but Render's edge caching won't cache them anyway due to their lack of file extension, so I didn't bother adding it.
All other routes get served the base index.html
entrypoint for Vite. We want this to be cached, but the HTML contains the filenames for all the other static assets, so we also want the edge cache to revalidate that it has not changed before serving it from the cache. This could be achieved with Cache-Control: must-revalidate, max-age=0
, but since Render's cache ignores files without certain extensions, this would also be ignored.
Froggy Chore's frontend is built using Vite, and the backend uses a library called vite-express to serve the frontend files. It creates an Express server and parses your Vite config to add handlers for serving your static files and HTML entrypoints.
The configuration for the static file middleware that vite-express adds can be customized by manually adding the middleware before starting the server. It takes the same options as express.static, which it uses under the hood:
const app = express();
app.use(ViteExpress.static({
maxAge: 31536000000 // 1 year in milliseconds
}));
const listener = ViteExpress.listen(app, 8000, () => {
console.log(`Your app is listening on port ${listener.address().port}`);
});
Since the other two types of requests are going to be ignored by the CDN no matter what we do, this was the only necessary code change.
I deployed the new code and made sure to enable the Edge Caching toggle in the settings for Froggy Chore's web service. All that was left was to confirm that my changes worked.
To test this, I visited https://froggychore.com/ with caching disabled in my browser devtools, and checked the requests to the JS and CSS files. The first time I hit them they had a cf-cache-status: MISS
header, which indicated that they were able to be cached but had not yet been stored in the cache. I refreshed the page and confirmed that they now had cf-cache-status: HIT
headers, indicating that they were successfully served from the cache.
Thanks for reading!