2024 Blog Setup

by Saketh Thota · 1/30/2024

One of my resolutions for last year was to start writing to document the things I learn and share my thoughts and opinions on tech related topics I find interesting. Unfortunately, I struggled to find a good workflow and platform to keep myself motivated.

After a lot of research and experimentation, I’ve settled on a platform that’s easy to set up, maintain, and publish. The source code for this project (this site) is available here.

Astro

Astro is a web framework that pioneers a frontend architecture called islands. Islands strip all non-essential JavaScript from the page reducing overhead, increasing perfomance and making Astro perfect for static sites like my portfolio. It even ships with Markdown support and a file-based routing system for a seamless experience writing and publishing a post.

For a very quick and basic setup, we can use the create astro CLI to create a new project and start writing immediately. Simply run npm create astro@latest to bootstrap a new project, and create new blog posts in the src/pages directory.

src/pages/post-1.md
---
title: Hello, World
---
# Hi there!
This Markdown file creates a page at `your-domain.com/page-1/`
It probably isn't styled much, but Markdown does support:
- **bold** and _italics._
- lists
- [links](https://astro.build)
- and more!

And that’s it! By default this Markdown file creates a page at /post-1.

MDX and Content Collections

This is a good start, but there’s 2 main reasons I wanted to use Astro that we haven’t touched on: MDX and Content Collections.

MDX is a superset of Markdown that lets users embed JSX components directly in your Markdown files. With MDX, we can create custom components to extend the functionality of our blog posts. For example, If we have want to embed a tweet but want to have interactivity and not just a screenshot, we can use Vercels React Tweet component directly in our markdown. To use MDX in Astro, run npx astro add mdx and begin using .mdx files.

Content Collections are a type-safe way to organize content and data in an Astro project. Content refers to any .md or mdx, and data refers to any .yaml or json. In Astro, any directories in the reserved src/content are automatically treated as content collections. To get all the type-safe goodness Astro provides, lets use zod and define a TypeScript-first schema for our blog post frontmatter.

src/content/config.ts
import { z, defineCollection } from 'astro:content';
export const collections = {
'blog': defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
publishedAt: z.string(),
tags: z.array(z.string()),
draft: z.boolean(),
}),
}),
};

From here we can move our posts to src/content/blog and query our collection to generate the routes needed for our blog’s static content.

src/pages/posts/[...slug].astro
---
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const blogEntries = await getCollection('blog');
return blogEntries.map(entry => ({
params: { slug: entry.slug }, props: { entry },
}));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<h1>{entry.data.title}</h1>
<Content />

Alongside blog related Markdown content, I also use content collections to store my portfolio projects in a collection of .yaml files. The files contain metadata that I use in the Project component, and the result is full TypeScript support when I query the collection, including property autocompletion and type-checking.

Extend w/ LaTeX and Expressive Code

I often include LaTeX snippets in my posts but Astro doesn’t currently support it. To add support, we can use remark with its math and rehype-katex plugins to parse LaTeX snippets and render them as SVGs. Just run npm install remark-math rehype-katex and add the following to your astro.config.mjs and index.astro.

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
markdown: {
remarkPlugins: [
'remark-math',
],
rehypePlugins: [
['rehype-katex', {}]
]
}
});

src/pages/index.astro
<html lang='en'>
<head>
<!-- Katex -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css"
integrity="sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ" crossorigin="anonymous">
</head>
<body>
<slot />
</body>
</html>

Code Blocks are already supported by Astro’s Markdown parser, but I wanted to add additional functionality like file names, line highlighting, and copy buttons. Expressive Code is a great integration of this that we can add to our Astro project by running npx astro add expressive-code. The result are the pretty code blocks you see in this post!

References

astro
md
typescript