Migrating my blog from Gatsby to Astro
- Move away from Gatsby. What sounded like a good idea, turned out to be a complete disaster. Probably one of the worst developer experiences I’ve seen (after React Native), with poor defaults, and unnecessary complexity with its GraphQL API.
- Stop shipping React. The pages are completely static, and using React to render them in the browser is unnecessary.
- Merge my homepage and my blog. The homepage is essentially a single-page site, and it doesn’t make sense to maintain it separately from the blog.
- Better represent the current me. The old homepage was focused on my open source projects, which aren’t an important part of my life anymore.
I had, however, a few technical requirements:
- Keep using React for templates. Many static site generators still use templates, like Handlebars, which makes them hard to work with. I started using JSX for templates many years ago and then switched to React. This is still my favorite way.
- Keep using primitive components for styling. I already have a component library that is based on primitive components (
Stack, and such), and it’s my favorite way of styling sites and apps.
After some experimentation, I settled on Astro and vanilla-extract.
The developer experience is super nice, especially after Gatsby, and Astro comes with most of the things one may need for building a blog or any other content site: file-based routing, content collections, Markdown with syntax highlighting, and much much better TypeScript support. The installation process is much nicer than Gatsby or Next.js. It’s very fast, the docs are comprehensive and well-written.
Probably, the only issue I had so far is that it often crashes after code changes, but looks like it’s not a common issue but some problem with my environment.
Astro has its own components that look like a very basic version of React components mixed with MDX, and we could seamlessly use React components inside Astro components:
In this Astro component, we import another Astro component (
Layout) and a React component (
<slot /> is similar to React’s
However, my favorite Astro feature is probably content collections, which allows us to create collections of Markdown or JSON files, type frontmatter fields, and have an API to fetch documents for a collection. Have a look at a comparison of rendering blog pages in Gatsby and Astro.
I couldn’t continue using styled-components with Astro if I wanted to ship my site without the React runtime: We can’t use anything with React Context, and styled-components rely on it for theming.
However, vanilla-extract comes with a lot of limitations:
- We need to write styles in a separate
- We cannot export React components from
*.css.tsfiles, only strings containing class names.
- We need to write
classNameall the time and use clsx to combine class names.
- It’s possible to create primitive components but we could only use known prop values (for example, we could write
<Flex alignItems="center">but not
<Grid gridTemplateColumns="auto 1fr auto">).
- Not enough reusable types, which leads to copypasting types from vanilla-extract.
- Nonsensical limitations like selectors can only target one element and can’t use a global class name, which produces convoluted unreadable, and hard-to-maintain styles in some cases.
- Leaking abstractions, for example, one could use Sprinkles in local styles but not in global ones. I know why these limitations exist but I need to know how the tool works inside to be able to use it, and think about it every time I write styles.
Overall, it feels like a huge step back in time for some 10 years or so. The developer experience feels similar to CSS Modules, though, with better types.
I found that the colocation and component model of styled-components are easier to use and maintain. I prefer to keep styles in the same file as my components and access them as components instead of keeping styles in separate files and working with CSS class names.
Vanilla-extract may work for a simple static site, like a personal blog, but I wouldn’t recommend it for a large app with a big team.
Here’s what I’d write using styled-components:
And here’s what it looks like with vanilla-extract:
The only thing I like more in the vanilla-extract version is accessing design tokens (theme) using an import instead of a function. We could do the same with styled-components, if we don’t need contextual styling (changing the theme for part of the app, for example, having a
I created a light version of my React component library, so I could create layouts without writing custom CSS:
Here, I’m using
Box primitive components to create a responsive layout for a site menu.
And I think I changed my mind about responsive props, and now I prefer objects over arrays:
Both require some learning and getting used to but the object notation now feels more readable to me. Vanilla-extract supports both.
I wish there was a better way to work with styles. Vanilla-extract does the job but the developer experience is far from great. Let me know, if I’m missing anything!
And have a look at the site’s source code on GitHub.