178 lines
8 KiB
Text
178 lines
8 KiB
Text
---
|
||
title: "From Angular to Astro: building a cheap (and fast) personal site with a blog"
|
||
description: "I rewrote my website from Angular to Astro to have a Markdown blog with no backend, keep hosting costs low and chase the four green Lighthouse scores."
|
||
pubDate: 2026-01-09
|
||
heroImage: "../../assets/photos/from-angular-to-astro/cover.png"
|
||
tags: ["astro", "aws", "seo", "performance", "ai", "migration"]
|
||
---
|
||
|
||
import { Image } from 'astro:assets';
|
||
import lighthouseScores from '../../assets/photos/from-angular-to-astro/gauge.png';
|
||
import hostingDiagram from '../../assets/photos/from-angular-to-astro/hosting-diagram.png';
|
||
|
||
I like technical challenges.
|
||
|
||
I know Angular very well and I used React a lot too. So at some point I wanted to try something different and people kept telling me: "look at [Astro](https://astro.build/)".
|
||
|
||
The main goal was simple:
|
||
|
||
- I wanted a blog
|
||
- I didn't want to build or maintain a backend just to publish posts
|
||
- I wanted the site to be cheap to run (and, if possible, a bit more *green*)
|
||
|
||
So… I rewrote my site. Angular SPA → Astro static site.
|
||
|
||
## Why Astro (for me)
|
||
|
||
For a personal website, most pages are content. Not "app".
|
||
And for content, static generation is just great:
|
||
|
||
- fast pages
|
||
- easy deployment
|
||
- no server to keep alive
|
||
- Markdown files for posts (simple workflow)
|
||
|
||
Astro also gives you a nice middle ground: you can keep the site mostly static, but still add interactivity when you really need it.
|
||
|
||
## The honest part: I used AI for most of the migration
|
||
|
||
I'm going to be super honest: I used an AI agent to do a big part of the work.
|
||
|
||
I read the Astro docs (just enough), then I basically jumped into development using AI, staying quite "high level".
|
||
I was more like a product owner: I described what I wanted, then I reviewed what the AI generated and I fixed the parts where it got lost.
|
||
|
||
This workflow was **fast**, but it has a cost: you can lose details if you don't stop and write things down.
|
||
|
||
Still, it was the right choice for this kind of project. I wanted results, not became expert in Astro, but, in the same time i don't want to lose the good part of development and the curiosity to know what's Astro can offer to me.
|
||
|
||
## Where the AI got lost (and where I had to step in)
|
||
|
||
Most problems were not on the backend side (there is no backend 😄).
|
||
The real issues were **UI** and **visual details**:
|
||
|
||
- moving layouts from Angular to Astro: spacing and alignment were often "almost right", but not correct
|
||
- animations: I have small fishes in the footer… that kind of thing is annoying to replicate if you don't see the final result
|
||
- dark mode: the AI can add a toggle, but it doesn't really "see" what is still wrong (colors, contrast, icons visibility, etc.)
|
||
|
||
So the pattern was always the same:
|
||
|
||
1. AI does 80%
|
||
2. I test and compare
|
||
3. I fix the last 20% manually
|
||
|
||
That last 20% is where you spend most of the time, really... this 20% cost me really a lot of LLM tokens.
|
||
|
||
## Content was the hardest part
|
||
|
||
The biggest pain wasn't the framework. It was **content**.
|
||
|
||
I had to rewrite pages and sections into **Markdown / MDX**, then make sure Astro renders them correctly (Astro has its own way and content collections are powerful but different if you come from Angular).
|
||
|
||
In the end it's worth it: now writing a post is literally creating a `.md` file and pushing it.
|
||
|
||
## Hosting: keep it simple, keep it cheap
|
||
|
||
For this site I didn't want any "platform magic" that becomes expensive with time.
|
||
|
||
A static site can be hosted in a very boring way (and that's a compliment):
|
||
|
||
- build
|
||
- upload to S3
|
||
- serve with CloudFront
|
||
- invalidate cache when needed
|
||
|
||
<div class="w-full" style="text-align: center; margin: 2rem 0;">
|
||
<Image
|
||
src={hostingDiagram}
|
||
alt="Hosting setup: GitHub Actions builds and deploys to S3, CloudFront serves the site as a CDN to users"
|
||
width={800}
|
||
height={200}
|
||
quality={90}
|
||
format="webp"
|
||
/>
|
||
<em class="text-sm block mt-2">My hosting setup: GitHub Actions → S3 → CloudFront</em>
|
||
</div>
|
||
|
||
|
||
No servers, no backend, no database.
|
||
|
||
And if the site is light, you also reduce bandwidth and compute. Not saving the planet alone, but at least I'm not wasting resources for a personal site.
|
||
|
||
### Costs (AWS): basically cents, unless you get real traffic
|
||
|
||
One reason I went with a static setup (S3 + CloudFront) is cost predictability.
|
||
|
||
For a personal site, storage on S3 is usually negligible (we’re talking cents/month for a few hundred MB).
|
||
CloudFront also has a generous "always free" tier (1 TB data transfer out + 10M HTTP(S) requests per month), which is more than enough for a normal personal blog.
|
||
|
||
The only “fixed” recurring cost I really consider is DNS: Route 53 hosted zone is $0.50/month (plus the domain).
|
||
And cache invalidations are free for the first 1,000 paths/month, so regular deploys don’t cost anything.
|
||
|
||
## Performance and the "four green gauges" obsession
|
||
|
||
At some point I started chasing Lighthouse scores like a videogame.
|
||
|
||
<div class="w-full" style="text-align: center; margin: 2rem 0;">
|
||
<Image src={lighthouseScores} alt="Lighthouse scores: 99 Performance, 100 Accessibility, 93 Best Practices, 100 SEO" width={800} height={200} quality={90} format="webp" />
|
||
<em class="text-sm block mt-2">Lighthouse scores for lorenzoiovino.com</em>
|
||
</div>
|
||
|
||
Accessibility was the most fun one. Lighthouse kept telling me: **bad contrast**.
|
||
So I had to choose better colors, especially for text and dark mode.
|
||
It's a small thing, but it makes the site nicer to read. And it's also just… the right thing to do.
|
||
|
||
Then there was performance, especially around:
|
||
|
||
- CLS (layout shift)
|
||
- render-blocking stuff
|
||
- images
|
||
|
||
### Fixing CLS and render-blocking (fonts + LCP image)
|
||
|
||
Two things that helped a lot:
|
||
|
||
- make Google Fonts non-blocking (`font-display: swap`) and avoid [FOIT](https://fonts.google.com/knowledge/glossary/foit)
|
||
- give priority to the hero image ([LCP](https://web.dev/articles/lcp)) and don't lazy load above-the-fold content
|
||
|
||
This kind of change is boring, but the result is visible (and Lighthouse stops yelling).
|
||
|
||
### Image optimization: the "Astro saved me" moment
|
||
|
||
In the old site, images were not optimized. Some were huge.
|
||
My first thought was: "ok, I know this… I can build an AWS Lambda that resizes and optimizes images on the fly, then put CloudFront in front".
|
||
|
||
I did similar things at work.
|
||
|
||
But… for my personal site it was too much.
|
||
More moving parts, more cost, more complexity.
|
||
|
||
Then I discovered something very nice: **Astro can optimize images at build time** (Astro Assets).
|
||
So I moved images into the project assets, used the `<Image />` component and let the build do the job.
|
||
|
||
Result: smaller images, automatic formats (like [WebP](https://developers.google.com/speed/webp)), no extra infrastructure.
|
||
|
||
That was a big win: less complexity, better performance, cheaper hosting.
|
||
|
||
## SEO checks: not only Lighthouse
|
||
|
||
Lighthouse is great, but I also used tools like [**Screaming Frog**](https://www.screamingfrog.co.uk/seo-spider/) to see issues in a more "SEO crawler" way (missing meta, duplicated titles, broken stuff, etc.).
|
||
|
||
It's a different view of the site and sometimes it highlights problems you don't notice when you just browse your own pages.
|
||
|
||
## What I learned (and what I would do again)
|
||
|
||
- Astro is a great fit for content sites
|
||
- static hosting is boring and boring is good
|
||
- AI can speed up the migration a lot, but you still need to review and fix the last details
|
||
- performance work is not "one big thing", it's a lot of small fixes
|
||
- accessibility is not optional -> it makes your site better
|
||
|
||
If you are thinking about moving your personal site to Astro: do it, "be quick or be dead". 🤘
|
||
|
||
<div style="display: flex; justify-content: center; margin: 2rem 0;">
|
||
<iframe width="560" height="315" src="https://www.youtube.com/embed/CTt1vk9nM9c" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||
</div>
|
||
|
||
Worst case you learn something new. Best case you end up with a faster site and a blog you actually use.
|
||
|
||
And now… the real challenge is writing posts consistently. 😅
|