The author Simon MJ Garrett
Sat Oct 05 2024
Main hero image

From SolidJS + Sanity.io to Remix + Markdown: Website Rebuild

As full-stack developers, we’re always on the lookout for tools and frameworks that can simplify our workflows and enhance performance. My recent journey from using SolidJS with Sanity.io as a headless CMS to building my site with Remix and Markdown was a fascinating one.

In this post, I’ll share why I made the switch, how Remix transformed my workflow, and how writing content in Markdown gives me more flexibility than using a traditional CMS like Sanity.

Why Switch from SolidJS and Sanity.io?

SolidJS is an excellent reactive framework that takes an unopinionated approach to state management and DOM updates. If you’ve used React before, SolidJS can feel refreshingly performant, particularly because it minimizes unnecessary re-rendering and eliminates virtual DOM overhead. It’s also smaller in size, which can lead to performance gains in certain projects.

On the content side, Sanity.io is a robust headless CMS that allows developers to structure content flexibly and query it using GROQ (Sanity’s query language). It’s API-first and provides real-time collaborative editing. However, despite its strengths, I found a few limitations with this stack:

  1. Complexity in setup and data fetching: SolidJS and Sanity.io required quite a bit of glue code to get them working together smoothly. Fetching and managing data across routes, handling authentication with Sanity, and ensuring optimal build times on content-heavy sites became a bit cumbersome.
  2. Dependency on Sanity.io: Relying on a third-party CMS meant dealing with potential downtime, API limits, and lock-in. For a smaller site or personal project, using a CMS felt like overkill.
  3. Content portability: While Sanity’s structured content approach is powerful, it made content less portable. Writing Markdown, in contrast, provides simplicity and flexibility to migrate content to other platforms.

Ultimately, I wanted a solution that reduced this overhead and gave me more control over the content and front-end rendering process. That’s when I turned to Remix and Markdown.

Why Remix?

Remix is a full-stack framework built on top of React (or any React-based system) that focuses on web standards and fast server-side rendering. Remix encourages thinking in terms of server and client with a unified API. What makes Remix stand out is how it treats routes as first-class citizens, how it minimizes JavaScript sent to the client, and how it encourages progressively enhanced applications.

Key benefits of using Remix:

  1. Better data loading strategy: Remix’s loader and action functions allow you to handle data fetching at the route level in a way that feels natural. It automatically deals with issues like race conditions, caching, and client/server synchronization.
  2. First-class support for nested routing: This fits perfectly with how websites are structured, and handling layouts or reusable components across pages becomes seamless.
  3. Server-side rendering (SSR) by default: Unlike SolidJS or traditional React SPA approaches, Remix puts SSR front and center, optimizing for performance and SEO.
  4. Less JavaScript sent to the client: Remix leverages web standards (like Forms, fetch APIs, etc.) so you’re not bundling unnecessary JavaScript just to handle basic web interactions.

Why Markdown?

With Markdown, content writing is simplified, and you get full control over how the content is processed and rendered. Here’s why I opted for Markdown over a CMS like Sanity:

  1. Simplicity: Markdown is plain text, lightweight, and incredibly simple to write. You don’t need a UI or a complex backend to manage your content.
  2. Content as code: By storing Markdown files alongside my code, I can version control my content in Git, enabling seamless collaboration and tracking of changes.
  3. Flexibility: Markdown integrates well with static site generators and modern web frameworks like Remix. It can easily be parsed and transformed into HTML during build or run time.
  4. Portability: Markdown is portable across platforms and tools. If I ever want to migrate my content elsewhere, I can easily move the files and adapt the processing logic.

Building the Website: SolidJS + Sanity.io vs. Remix + Markdown

Site Architecture with SolidJS and Sanity.io

When I built my site using SolidJS and Sanity.io, I structured it as a React-like app, focusing heavily on client-side interactivity. The main flow looked like this:

  1. Front-end (SolidJS): Managed client-side state and interactions. Data was fetched on component mount, often leading to waterfalls of requests as different parts of the page loaded.
  2. CMS (Sanity.io): Provided content storage and served content dynamically via API queries. Pages were rendered after content was fetched, adding complexity to caching and SEO.
  3. Build Process: SolidJS apps required custom tooling to integrate with Sanity’s real-time API, and sometimes rebuilding the front end to reflect content updates was slow.

Site Architecture with Remix and Markdown

In contrast, Remix simplifies the architecture while improving performance:

  1. Front-end (Remix): Remix handles the routing and state management via its loader functions, which makes data fetching predictable and synchronous with navigation. Since Remix preloads data server-side and sends HTML to the browser, the user sees content almost instantly, avoiding client-side rendering delays.
  2. Content (Markdown): All my content now resides in Markdown files stored locally, which I parse using tools like gray-matter and remark. During the build process, Remix reads these Markdown files, converts them into HTML, and injects them into the relevant pages.
  3. Build Process: Remix’s build process is fast and optimized for SSR. By eliminating the need for API calls to a CMS, I have complete control over content delivery. With Markdown files, I can pre-generate all pages at build time or load the content dynamically when a user requests it.

Practical Example: Listing and Rendering Markdown Posts in Remix

Let’s take a quick look at how I transitioned my blog from Sanity.io to Markdown.

First, I created a posts directory in my project:

/app
  /posts
    post1.md
    post2.md

Each Markdown file includes front-matter for metadata like title, slug, and date:

---
title: "My First Post"
slug: "my-first-post"
date: "2024-01-01"
---

# My First Post

This is the content of my first blog post. Markdown makes it easy!

I wrote a utility function in Remix to parse these Markdown files using gray-matter:

import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

export function getPost(slug) {
  const postPath = path.join(__dirname, 'posts', `${slug}.md`);
  const file = fs.readFileSync(postPath, 'utf8');
  const { data, content } = matter(file);

  return { metadata: data, content };
}

Then, using Remix’s route-based data loading, I could dynamically load and render the post content:

export const loader = async ({ params }) => {
  const post = getPost(params.slug);
  return json({ post });
};

export default function Post() {
  const { post } = useLoaderData();
  return (
    <article>
      <h1>{post.metadata.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

Final Thoughts

Transitioning from SolidJS and Sanity.io to Remix and Markdown has been a revelation. With Remix, I’ve streamlined data loading and significantly improved performance with SSR. Writing in Markdown gives me flexibility and control over content, making the whole process simpler, faster, and more maintainable.

If you’re considering switching to Remix and Markdown, you’ll find a lot of power in this combination for building websites that are fast, easy to maintain, and content-driven.