Building a zero runtime dependency blog without a framework

2024-05-31 3 min read

Building a zero-dependency blog with Typescript, Markdown, and CSS

Faced with the prospect of creating a new blog, I decided to build one from scratch.

I hacked around for a day and this is what I came up with.

For context, I've spent a lot of time with React, Next.js, and Gatsby. I wanted the ergonomics of a modern JAMStack framework (dev server, markdown content, SSG), but without shipping a whole copy of React to the client.

Here are the different approaches I've used in the past:

For fun, and a challenge, I decided to build a zero-dependency blog using Typescript, Markdown, and plain-ole HTML & CSS. Orchestrating builds with a simple Node script, and using Remark/Rehype to pre-process the Markdown. It ended up being a nostalgic throwback to the days of task runners like Gulp and Grunt.

And in the end: look ma — no JS. 😎

Network tab with no JS

That's not to say that there's no JS involved at all, I ended up cobbling together a few NPM packages to help with the Markdown processing and the dev server. At the time of writing, the stack is:

Package(s)Description
node tsxThe build process is run from a single ~150 line NodeJS script, mainly making use of thfs and path modules to pipe files from src to dist with light modifications, and to transform markdown into HTML. I use tsx to run node scripts written in TS, with transpilation done on-the-fly.
handlebarsI use handlebars as a templating engine to inject re-usable partials into the HTML, e.g. nav bar, document head.
unified remark rehype highlight.jsThe build script uses a unified pipeline for parsing markdown with remark and transforming it into HTML with rehype, with some plugins to inject additional html (e.g. nav bar) and do syntax highlighting with highlight.js, which is then inserted as a handlebars partial.
nodemon http-server concurrentlyRoll-your-own dev server. nodemon watches for file changes and re-runs the build process. http-server serves the html during local development, and this is all orchestrated with concurrently to wrap running multiple processes.

And that's it! Thanks for reading.