Reaching for the Stars with Astro

Published Sunday, November 27th 2022 · 8min read

I’ve always loved static websites, that’s no secret. I mean, I even built a CMS to fix their biggest drawback: editing content. Building a website with HTML and CSS just makes sense to me, although obviously using just HTML and CSS isn’t nearly as much fun as using a static site generator. I feel at home in the Jamstack, and while I have used website-as-a-service companies such as Jimdo and Squarespace before, I always ended up fighting with their way of doing things (and making things look) at a certain point. I certainly also gained plenty of experience working with WordPress this past year, but I just can’t warm up to it. These three (and all the others) are certainly viable ways to build a website nowadays, yet all but the Jamstack seem less than ideal for most projects to me.

I also really like working with Vue, but shipping a website as a single page app probably isn’t the best idea, so I was delighted when I stumbled across Gridsome. I had worked with VuePress before, but while it was great for documentation websites, it seemed less useful for something like an online portfolio or a company website.

Good, but old, Gridsome

Gridsome just felt right. It came with a clever data-layer, image optimisation and link-preloading out of the box. Working with it felt intuitive once I had grasped the basic concepts of GraphQL, and I was very happy with it despite some of its quirks for the longest time. I’ve built everything with it, ranging from this blog to multi-language websites for different companies. Unfortunately, there hasn’t been a new release since November 2020 and while there seems to still be some development happening, the future of the project doesn’t feel very certain.

Landing on Astro

So, I decided to look for alternatives. On top of VuePress, there’s now also VitePress. There’s obviously Nuxt, which only recently released version 3.0, and then there is Astro. The new kid on the block. Hyped for a while and recently released in stable form. No-JS by default, with fast build times courtesy of using Vite instead of Webpack, and with support for not only Vue, but also plenty of other modern frameworks such as React and Svelte.

I was sceptical at first, as I tend to be with things that look too trendy, but as I read through the docs, it resonated with me. It felt a lot more simple and intuitive than Eleventy, another (slightly hyped) static site generator with a lot of flexibility.

Project Setup

Scaffolding a new project is easy by simply running npm create astro@latest, which guides you through the process playfully. There are not too many choices to be made up-front, which is refreshing, and the recommended “a few best practices” setup provides everything needed to get going right away. The only thing I dislike is that there’s no option to disable TypeScript entirely, and the “help me choose” option of the menu allowing for selecting the strictness of the TypeScript integration simply chooses the most relaxed setting without much explanation.

As a bonus, there is an extension for VS Code available that make working with Astro Components and pages easier—and this extension is officially available on Open VSX, which is a big plus for users of VS Codium. Astro has a focus on developer experience, and it shows.

A Universe of Possibilities

Once set up, a project should feel familiar to anyone who has worked with a static site generator before. There are Layout files that allow creating basic page scaffolds to load content into, which lives in a pages directory. Every file in that special folder, be it an HTML or Markdown file or an Astro Component, automatically turns into a page on the final website through the magic of file-based routing.

This is already enough to quickly set up a personal blog, or a simple personal website, but the possibilities only grow from there. Markdown front-matter exists in Astro Components as well, making it possible to pass data beyond the content to pages. There are options for dynamic routes through special filenames and the createStaticPaths() function, pagination options for large collections, and Astro can even run in a server-side-rendering mode, allowing a static site to be turned into a dynamic one somewhere down the line.

And all that without shipping a single line of JavaScript to the client by default, which shouldn’t be such a big thing, but apparently is with all the client-side hydration that’s been going on in the past few years.

Astro Components

So, how do you get JavaScript to the client when you need it, say for a dynamic image carousel or a light box for your photos? Astro calls these use-cases “islands of interactivity”, but you may not even need them if you make use of their custom component format, Astro Components, which are written in .astro files.

In their words:

Astro components are the basic building blocks of any Astro project. They are HTML-only templating components with no client-side runtime.”

They allow developers familiar with the component pattern of many UI frameworks such as Vue, React, or Svelte to work in their usual manner by splitting and reusing functionality across multiple smaller components out of which to assemble the final user interface—all without the overhead of such a framework, since in the end it all gets compiled down to HTML, CSS and optionally JavaScript during the build process.

These components can have data passed to them through props and even allow arbitrary content through slots, which is in fact how layouts work in Astro. They are simply Astro Components which accept a range of props, for example to set the <title> tag of a website, and a slot, which displays the actual content of the individual pages making use of the layout.

The template of an Astro Component can be plain HTML, but also supports a form of JSX, a templating language that will be familiar to any React developer, which allows for dynamic HTML and greatly improves the developer experience when working with sets of data such as lists, as it allows for for-Loops and conditionals.

Astro Components can also contain <script>-blocks, which is how interactivity can be achieved without falling back to a UI framework. These blocks are processed by the bundler, Vite, so you can write modern JavaScript, complete with npm module imports, TypeScript and all.

Oh, and CSS scoping and pre-processors are supported out of the box as well, courtesy of Vite! Simply install sass, stylus or less and use <style lang="scss"> in your component’s style block.

But I don’t Like JSX

If you’re like me and prefer the way of writing component templates using directives like in Vue, Astro has you covered as well. There are so-called “integrations” for many of the big UI frameworks, including Vue, and they can be simply added by running npx astro add name-of-integration.

Once everything is installed and configured, which happens automagically, you can simply write and import Vue components as you would in a Vue project. They can even be used within Astro Components!

But there’s a catch—well, a feature. Even with an integration such as Vue running, Astro still produces a zero JavaScript build by default. All Vue components get rendered to plain HTML during the build process and won’t be hydrated on the client! This is great for page speed and accessibility, but not so great for your image carousel or light box components.

This is where the “islands of interactivity” come to play. Using special directives, such as client:visible, Astro can be instructed to hydrate specific components on a website immediately, once the component becomes visible, or when the CPU is idling. It’s the best of both worlds.

Working in Space, well Astro

So far, I’ve only used Astro for some small landing pages, but the experience was quite good. Coming from Gridsome, it took a bit of adapting to get comfortable with the way Astro handles things, especially regarding interactivity with JavaScript. I’m surely bound to stumble across some more challenges as my Astro projects grow more and more complex, but I’m looking forward to tackling them in the near future—I might even take the plunge and re-write this website with it eventually!

Here’s what I like:

  • Carefully thought out developer experience
  • Framework-independence
  • Speed both during build (thanks to Vite) and after deployment
  • Active development with some fresh ideas
  • And upgrade-path to a server-side rendered website if needed
  • Extensions such as image optimisation are available, but optional

And here’s what I didn’t like so much:

  • Feeling forced to use TypeScript—it should be a choice!
  • It’s hard to style Astro Components when they are used within other components because of style scoping (might be a bug)
  • No attribute inheritance in Astro Components, adding a class to a component doesn’t work and passing classes as props seems needlessly cumbersome
  • There’s no separate, clearly defined data-layer as in Gridsome (could also be a benefit though, but I feel that this might become an issue in larger projects)
  • URL handling is a bit cumbersome when using a base-URL

Personally, I’m also not a big fan of the JSX-syntax in Astro-Components, but that’s a matter of taste and not really a drawback, especially since it’s possible to use your favourite UI framework of choice while still benefiting from the performance improvements and features of Astro.

I think I also still have to learn and figure out some ways of building modular sites with Astro without hydrating basically everything—but that’s part of the process.

All in all, I’ve enjoyed my experience so far and if you’d like to try out Astro for yourself, they have an interesting tutorial in their documentation that teaches you how to build your own blog.

I hope you enjoyed reading this article, and if you have any thoughts to share, please feel free to do so on Mastodon or Twitter. Thank you for your time, and I’ll be back for the last post of 2022 next month!


I am not affiliated with Astro in any way, nor was I asked or received any form of compensation for writing this article. All my experiences and opinions about it are my own.