Posts

Generating a Blog with Vite, MDX, and Remix

The Site

This site is built on top of Remix, which has many features that I absolutely love, but perhaps by favorite is its nested routing/route file name conventions/route module interface. It's the main selling point in my mind.

Here's how it works: 1. Create a file conforming to the Route naming patterns (posts.my-post.tsx => /posts/my-posts) 2. Implement and export some or a subset of the Route Module "interface" 3. Done

The Route Module is super powerful with 3 main exports:

  1. default: a react component to be rendered in the route hierarchy (optional)
  2. loader: a request handler for handling reads (optional)
  3. action: a request handler for handling writes (optional)

The power comes from how Remix uses this simple interface to let users build super-speedy React Apps with Server-Side Rendering. Plus, you get to write (some) of your server-side and client-side code in the same file, which is a magical feeling.

The Posts

Not only does Remix support JSX and Typescript, but it also supports (via a plugin) MDX, a technology so absurd. MDX. JSX/Javascript inside markdown.

But it's not like you think, at least not for me. I'm not writing lots of Javascript in these files. You can, but it's not an amazing editor experience. Syntax highlighting is pretty good, but Markdown heavily relies on blocks/new lines, which JavaScript largely ignores (good ole' ASI), sometimes leading to oddities.

What's particularly impressive is a) Traditional front matter support. b) Module exports. c) The ability to reference decoded front matter in the MDX module, like so:

---
title: Coding my Resume
meta:
  - name: description
content: Because formatting word documents by hand is too easy, but also not.
---
 
export const meta = [
	...frontmatter.meta,
]

This capability to export values allows an MDX module to fulfill the Route Module interface requirements, and referencing front matter within the module helps keep things DRY (Don't Repeat Yourself).

The Challenges

A blog, or digital garden, is typically more than just a collection of posts. It involves managing metadata and relationships, such as tags, categories, and indexes. Creating a feature-rich blog with content stored in MDX files presents several challenges.

Keeping bundle size low

Since we use Vite, where each post is a module, we can utilize import.meta.glob(**/*.mdx) to import all or selected posts. However, we must prevent Vite from creating a massive bundle containing every blog post when only a few are displayed.

Building indexes

We can place metadata like tags and categories in the front matter or export them as mentioned. However, importing these modules must be handled cautiously to keep the bundle size small. Additionally, in a serverless environment, these indexes are rebuilt with every request unless some form of caching is implemented. While this might not be an issue for ten blog posts, it doesn't scale efficiently.

What's next

I'd like to separate my website architecture and content architecture. I want more control over the lifecycle and metadata (like changes) I make to posts, and I want more performant indexes, which means persistence.

More importantly, since that is the point, I want a better writing experience. I really like writing in Obsidian, but it's pretty much a non-starter with its own Obsidian Flavored Markdown.