Priyanshu Nayan

Improving the performance of my Astro Blog

I have been meaning to try out Astro for a long time. I finally got around to it. I really liked that it didn’t spit out any JS that I didn’t write. It did exactly what a static site generator needs to do, and it did it really well. Unlike 11ty, which I also love, you don’t need to use any templating engine. HTML, CSS, and JS are all that you require. I also liked this.

No JS is the best JS 💛

No JS is the best JS 💛

Since I was already using Astro, I wanted it to be as fast as possible. So I headed over to PageSpeed and ran the analysis. The page is really simple: an introduction, a bunch of images, and some more text. I was expecting it to be fast by default. The first run with no optimizations gave a performance score of 93, which is decent but there is definitely scope of improvement.

first-run.jpg

One of the good things about PageSpeed is that it also provides actionable suggestions. Looking at the suggestions, the one that seemed to stand out was improperly sized images. Four images were taking 0.42 seconds to load, which is not good. I needed to figure out exactly what the issue was. Fortunately, Resplint came to the rescue. I bookmarked it and clicked on it for the page that I was analysing.

Running the analysis showed issues with two images - both of them had the same issue:

“The displayed image was 376px wide, but the received image was 1283px wide.”

Untitled

Untitled

So, we are sending a bigger image than is required. This, in turn, is contributing to longer load times. So, how do we reduce it?

For context, these images were directly coming from Product Hunt’s CDN, mainly because why not? It required less effort from my end and used their bandwidth. However, this approach did not work.

Fortunately, I had access to Cloudflare Images. One of the benefits of a CDN is that it can do dynamic optimization. Dynamic optimization is always better than static optimization, which is generally done during build time. There are only a few variations that you can generate with static optimization. Dynamic optimization looks at the user agent, determines if newer image formats can work, sends them if not, and falls back to the original format. It also compresses on the fly. So modern machines get modern formats, while older machines get old formats. Win-win.

So the next step was to figure out if we could tune the settings in Cloudflare to get the best possible deal. It turns out it’s a real piece of cake. You just need to turn on the flexible variants.

Untitled

And now you can pass the width in the URL. So, passing the width as 376, which was required, Resplint runs without error.

Untitled

Let’s run the test again.

We got a performance score of 94, which is 1 level higher. No problem. Moving on to the next action items.

Untitled

One other suggestion was that images should have explicit width and height. It was surprising for me because If we provide explicit width and height, how can they be responsive? Thankfully i got to know that modern browsers use width and height to set the default aspect ratio of images, we need to set those attributes and have this piece of CSS to make them responsive too. Best of both worlds.

img {
  width: 100%; /* or max-width: 100%; */
  height: auto;
}

Now let’s run the test again. Still at 94%. Holy moly! Did all these changes amount to nothing?

Untitled

FCP and LCP is still in red. Also now, we don’t have any actionable suggestions, we can only guess.

Guesses:

  • Lazy load images:
    • No improvement.
  • CSS looks a bit more than expected; let’s try compressing it.
    • No improvement in score.
  • Instead of chaining stylesheets, which are blocking in nature, what if we inline required styles and load the stylesheet asynchronously?

Untitled

  • Inlining critical styles significantly boosted the score. we are at 99 now!

Untitled

How do we get that one point?

  • One guess is that since I am using Inter, it may be contributing to CLS. Let’s try reducing the CLS as much as we can by using the fallback font. Still no luck.

Moving back to the docs, how does Astro suggest loading web fonts? It turns out that they recommend using font-source. Fair enough. I removed the link tag, used the font source, and ran the analysis again, and voila, 100!

The reason I think that might be is that font source used the Critical FOFT variant. This is known to be the most performant approach. In this approach, we load only essential CSS before loading the rest. When it comes to typography, the only critical things are letters A to Z (both capitals and small letters). We can create a subset of these fonts with unicode-range. Thankfully I did not have to write these ranges by myself.

Untitled

Running the analysis again:

https://pagespeed.web.dev/analysis/https-personal-blog-six-tau-vercel-app/oafby2mxcx?form_factor=mobile

https://pagespeed.web.dev/analysis/https-personal-blog-six-tau-vercel-app/oafby2mxcx?form_factor=mobile

We now have the perfect four. Without the tools that we have today, it would have been next to impossible. Nevertheless, it was fun working with Astro because minimal time went into figuring out the tool and I was able to work on the actual web issues. I was able to hack this little website together within a night!

I post more frequently on Twitter. Follow me there to see what I am upto these days!