If you’ve visited my site in the past, you’ll likely find that visually it looks mostly unchanged. But under the hood, nearly everything has changed. That’s because I recently decided to rewrite the previous version, built with NextJS, with one built with Astro.
In this post, I’ll talk about why I settled on Astro, some of the main features I like, a few unexpected delights, and some of the (mostly minor) downsides I discovered.
Deciding on replacing NextJS
This all started with me reviewing the current codebase and running npm-check-updates in my code repo, only to be greeted by a sea of red.
As I started digging into what specifically was outdated, the old version of NextJS (v12) really stood out. I briefly looked into updating to the latest version (v15), but with the current app using the old page router model, just the process alone of updating to use the new app router seemed like a lot.
NextJS just felt like overkill for a mostly static site with a blog.
But more significantly, the code base overall had started to feel outdated and
in need of an overhaul, and using NextJS, in particular the idea of going
through a possibly extensive updating process, just seemed like overkill for a
mostly static site with a blog.
So it was time to shop around for a more light-weight, modern alternative.
Why I settled on Astro
Picking a new JS framework these days is a bit like when you go to a classic diner and are presented with a seemingly endless menu.
With so many available options,
it’s important to have a clear understanding of what you want or you’ll likely find yourself feeling overwhelmed.
So, I started by first jotting down the features that were most important to me:
Optimized for static, content-rich sites, but can also support more advanced functionality if needed.
After a bit of research, I had narrowed my choices down to the following two candidates: Svelte and Astro. (Qwik and Htmx were also top contenters but in my very subjective evaluation were not a good match for me.) In the end, I decided to go with Astro, which checks all of the above boxes and much more.
Here are a few of the main reasons why, as well as some challenges I encountered.
MDX and other “batteries” included
All my current blog posts are written in MDX, which is basically markdown but with support for inline components, so supporting that was a must.
With the old version of the app, quite a bit was required to get MDX working, including installing and configuring next-mdx-remote, and multiple other packages to allow for reading the mdx format, handling frontmatter, displaying code with syntax highlighting and more.
If I had stuck with the new version of Next, there would still be quite a bit
of config
required.
With Astro, just run npx astro add mdx, follow the prompts, and you’re good to
go. 🎉
Discovering the Astro automatic integration setups was definitely a bit of a
delighter.
This is thanks to their numerous automatic integration
setups for their
official integrations, which includes mdx. (As an aside, I can’t understand why
NextJS doesn’t add these types of CLI features, but that’s a topic for another
day.)
So much of what I had previously needed to set up manually just worked out of the box, including the above-mentiond handling of frontmatter and code syntax highlighting.
Bringing markdown lightness to component files
I remember the first time I encountered markdown. Coming from years of working with HTML, I just took one look at it and it immediately made sense.
In many ways, the Astro component file structure applies markdown thinking to component files, which means basically zero learning curve if you already know React, and a lot less code to write to achieve the same result.
For comparison, here is (a simplified) React version of my previous homepage…
All the code that runs strictly on the server is enclosed in the equivalent of a markdown frontmatter block. Everything below that block (the ---) runs both on the client and server. Note that there is no need to include a function export or to name your component in the file.
And we cut the number of lines of code by about a third. 🎉
Everything except for the jsx is optional. For a minimal component, the difference becomes even more pronounced.
In this case, we went from 15 to 3 lines of code. 🔥
Note how it’s not even necessary to name your component within the file as it’s just a default export and you can name it whatever you want when importing, though I’d strongly recommend having that name match the name of the file.
I assumed I’d still need React, but apparently not
As I mentioned earlier, one of my requirements for the selected framework was to allow for continuing to use tools I already know, such as React. I just assumed I’d need it for more advanced features.
But time and again, I would start porting over some feature, and then realize React wasn’t needed. In the end, I was able to add all the current features without React.
Very often, you can just replace React with a generic js equivalent.
The general pattern, I found, is that you can usually just replace some
react-specific package with a more generic or framework-agnostic equivalent.
(And this is not something specific to Astro, but a general trend among newer
frameworks.)
For example, in the previous version I was using react icons for display of icons. In the new version, I was able to quite easily replace it with the frameowrk-agnostic iconify.
And the best part is that if I should encounter a feature for which I can’t find a good generic version, well, adding React is always an option.
Some mostly minor downsides
As I mentioned above, there were also a few downsides I discovered in making the switch to Astro. One of them was only allowing a single component per file.
One component per file
In many cases, I’ve found it preferable to be able to sub-divide a larger component into a set of smaller sub-components, but with Astro that meant I had to place all those in a folder, create a file for each sub-component and then import into the main component.
Yes, kind of a pain, but to be honest, having multiple components in single file is probably not a good practice, so I guess in some ways this was Astro forcing me to eat my broccoli. 😊
Mysterious linting errors
One oddity of Astro I encountered were some mysterious errors I’d see when importing what appears to be a native Astro module.
As it happens, that error message isn’t quite accurate. Running astro dev is not sufficient, and even restarting your language server didn’t always help.
Instead, when I see these errors I need to run the astro sync command, which re-generates types for content schemas and more.
Apparently, I was not the only one who was confused about this. Even though the issue is closed on Github, I was still experiencing it as of this writing.
I could continue to list a number of additional issues I encountered, but they were in most cases minor. Overall, I’m quite happy with having made the switch to Astro.
A first step in moving away from React
For me, maybe the most significant aspect of this update is the move away from React. I’ve been using almost strictly React for so many years now, it was definitely eye-opening to see that, at least in it’s current form, it simply is starting to feel dated.
If you’re thinking of standing up or replacing your mostly static site, definitely research all the current available options out there (and before doing so, save yourself some headache and list your specific requirements), but definitely take a look at Astro as well.