I wanted to take some time to write my first blog post using markdown (MDX) in Remix. Writing content in MDX is extremely easy and allows integration across various platforms. I drew insperation from the Remix blog, Pedro Cattori, Brad Garropy, Raj Talks Tech, and Kent C. Dodds to create my own blog. Piecing together the various parts of the code to create this blog was a fun and educational experience. There are a few things that make this deployment unique. First, I am using Remix as the framework to build this blog. Remix is a full-stack framework that allows developers to build web applications using React. Second, I am using Vercel for deployment. Vercel is a cloud platform that allows developers to easily deploy web applications in a serverless environment. I am using MDX to write my blog posts. MDX is a markdown syntax that allows you to write JSX in markdown. This allows for creating dynamic content that can be rendered for the client. I am also using Tailwind CSS and Shadcn UI for styling and Cloudinary to host the images. Finally, there is an integration with Prisma for a PostgreSQL database to store my mailing list and future expansion of user accounts. The code can be found on my GitHub Page.
To get started, I created a new Remix project. Then, I installed the necessary packages for MDX support:
Depending on your stack and needs, you may have to install slightly different packages. In my case I am using Remix.run with the vite plugin. My vite.config.ts file looks like this:
This configuration file sets up the necessary plugins for MDX support out of the box. The mdx plugin is used to compile MDX files. The remarkPlugins and rehypePlugins options are used to configure the plugins that are used to parse and transform the MDX files. The remark-frontmatter and remark-mdx-frontmatter plugins are used to parse the frontmatter in the MDX files. This setup works great if you have a few posts or a small blog with each individual post saved in a separate route file. However, if you have a large number of posts, you may want to consider using a server to serve the posts dynamically. This is the approach I took for my blog with the help of mdx-bunder by Kent C. Dodds.
The blog post server is set up in my utils folder and is named posts.server.ts. This file reads the blog posts from the file system and serves them to the client. The server is set up with a few essential functions; first, there is the getPostFiles function:
Then there is the 'getPostBySlug' function:
The getPostBySlug function relies on the compileMDX function to compile the MDX files and ensure they are formatted appropriately. In this function I use the Remark TOC, Remark Prism, and Remark Gfm plugins to enhance the formating of my posts. The 'compileMDX' function is defined as follows:
Next, I set up the getPosts, getTopics, and getFeaturedPosts to dynamically pull in the posts information to the index.tsx route file. These functions read the metadata from the MDX file's frontmatter.
All blog posts are stored in the app/posts directory. I set up a blog.tsx and blog.$slug.tsx files in the routes directory to handle the blog post routes. The blog.tsx file is used for formatting with a Remix <Outlet>. The blog.$slug.tsx file displays an individual blog post. The blog.tsx file is setup as follows:
You can use whatever styling you like for your blog posts. I chose to use the Tailwind CSS prose class for styling by creating a prose.css file in the styles directory. The prose class is used to style the blog posts and make them more readable. Specifically for adding code highlighting. The prose formatting I used is from Kent C. Dodds.
I hope this post has helped you understand how I set up a blog using MDX and Remix. I have enjoyed the process of creating this blog and look forward to writing more posts in the future. If you have any questions or comments, please feel free to reach out to me on X. I look forward to hearing from you!