Moving this site to Astro
After about three years running on Jekyll I started to get frustrated at some of the stuff I couldn’t do easily - primarily the difficulty of working with custom components in markdown. I was using some kinda-janky markdown pre-parsers to let me insert things like callouts…
{:.callout}This is a calloutWhich wasn’t exactly easy to work with and more importantly, if I ever decided to switch away from jekyll and export all my markdown files, isn’t exactly obvious or intuitive.
What I really wanted was the ability to use HTML- or React-like components in my markdown. And as with web components or react components, I wanted to define these as self-contained components with scoped CSS and the like.
So in early 2023 I started playing with AstroJS . The most appealing thing about it was the native support for MDX , its React-like component architecture where .astro files contain scoped HTML, CSS and JS, and the relatively small amount of boilerplate needed to get a blog up-and-running.
I quietly ported this site over to Astro, but with the release of Astro 3.0 in August ‘23 so much had changed that it made more sense to start again from scratch. So I switched to the current codebase around the time Astro 4.0 dropped in December ‘23.
Why Astro?
Modern, Simple & Content-First
Astro is very well designed, and because it’s built with a modern typescript-based stack, it comes with all the advantages you’d expect (typesafe javascript among them).
When used as an SSG, Astro is also very simple. File-based routing, markdown parsing and YAML frontmatter Just Work™ and stuff like image optimisation come out-of-the-box. And while composing pages from astro components feels very Reactish, it’s “zero Javascript by default” – the generated site will only include client-side JS when necessary, which for this site is hardly ever.
Astro has an extremely strong ecosystem of plugins, tools and themes around it.
Astro Components & MDX
Components can be anything from a tiny snippet of HTML to a reusable UI component (which takes props and/or content) to a whole page layout. Here’s an example.astro component:
---const { title } = Astro.props;const theNumber = Math.random();---
<section class="mything"> <h1>{title}</h1> <p>Number: {theNumber}</p></section><style> h1 { color: red; }</style><script is:inline> alert('Hello');</script>- The TypeScript in the component script at the top runs only at build time. The ability to co-locate this “server-side” code with the component is useful for keeping things organised.
- The component template (below the last
---) is the HTML which will be rendered when the component is used, except (much like JSX) you can use variables defined in the component script , or other astro components imported in it. - The CSS in the style tag is scoped to this astro component only.
- The script tag at the bottom uses a special astro directive, and will be executed client-side.
Building a site using Astro components is much the same as using react components (or partials in other SSGs). But the real power is using them inside Markdown Content.
MDX Components
MDX lets you use JSX inside markdown files, and is one of the main reasons I chose Astro over other SSGs. In Astro, you can import .astro components into mdx files and use them in the same way you can anywhere else. I’ve ended up with quite a lot of really simple components which just render some HTML and apply some scoped CSS to it. Here’s my highlight.astro component:
<span class="highlight"><slot /></span>
<style> .highlight { background: var(--color-highlight-bg); padding: 0 8px 4px; border-radius: 4px; }</style>And now when I’m writing in markdown I can use it like this:
Here is some text <highlight>that is highlighted</highlight>.And with more complex components like callouts…
<Callout emoji="💡" type="blue"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Earum hic a dolorem ipsa labore cum.</Callout>…which renders…
The combination of Astro’s component-based architecture and components-in-MDX-files ticks some important boxes for me:
- Components make for easy maintenance long term, especially when dealing with CSS.
- Scoped CSS and JavaScript mean I can iterate on styles without worrying about breaking other parts of the site.
- Using components in Markdown makes it extremely easy and quick to write fully featured content.
- If I ever want to switch away from Astro, the structure of Astro components and how they’re used in Markdown files should make it fairly easy to port my content to another system.
So Where am I now?
Two years into running this site on Astro, I’ve settled into a setup that gives me everything I need without much fuss.
Content Collections
The site uses two main collections: Articles and Notes. Articles are long-form pieces like this one – they live in /writing/ and support cover images, tags, and a bunch of other metadata. Notes are shorter, usually links to interesting things I’ve found with a bit of commentary. They’re deliberately minimal: just a title, optional source URL, and publication date. Both use the same filename pattern (YYYY-MM-DD-slug.mdx) which keeps things organised and makes it dead simple to create new content.
Plugins
I’m using a handful of plugins that handle the boring stuff so I don’t have to think about it:
- Expressive Code handles syntax highlighting for code blocks.
- Astro Icon lets me use SVG icons without manually importing and managing them. I can just drop
<Icon name="heroicons:home" />into any component. - Sitemap generates a sitemap.xml automatically, which is one of those things that’s trivial but annoying to maintain by hand.
On the markdown processing side, I’m using a few rehype plugins:
- rehype-autolink-headings adds anchor links to headings (so you can link to specific sections)
- rehype-external-links automatically opens external links in new tabs
- rehype-mermaid renders mermaid diagrams at build time.
I’ve also got a custom remark plugin that calculates reading time for articles.
Components
I’ve got about fifteen components in src/components/mdx/ – things like <Callout> for highlighted notes, <Accordion> for collapsible sections, <BookmarkCard> for pretty link cards, and <Notion> for embedding Notion links. Nothing fancy – just small bits of HTML with scoped styles.
The page layouts are simple – components like BaseHead, MainNavigation, and Footer get composed into layout templates like Article.astro and Note.astro, which wrap the markdown content. The whole design system is based on CSS custom properties defined in global.css, so switching between light and dark themes (or tweaking colours) is just a matter of changing a few variable values.
Future Plans
There are some notes & ideas on GitHub , but I’m not in a particular rush to ship any of it. I’d rather spend my time working on Astro Editor or using it to write stuff here.