Morgan Conrad

Client Side Markdown for a Website

Tags: all JavaScript     Nov 14 2021


I'm a co-owner of a 30' sailboat, and we wanted to build a website for it. To be honest, mainly because the .yachts domain was available, and, well, how cool is that? Normally I would have used a static site generator like Metalsmith. I considered learning one of the newer, "trendy" platforms like Eleventy, Gatsby, or SvelteKit.

However, as noted in the Cloudflare briefing. these tools have a disadvantage: "No user-friendly interface: It is harder for non-developer users to publish content using a static site generator." My two co-owners are computer literate, but far from running a remote build step or deploying via git. It was important that they be able to contribute content fairly easily.

A couple of years ago I ran across a neat and novel approach, CMS.js, a "Client-side, JavaScript Markdown Site generator in the spirit of Jekyll". There is no clientserver-side-scripting in Javascript or PHP, no "build step", no deploy via git, no real logic on the server at all. It just serves files. One need simply deploy markdown files to the server, using something like FTP. My buddies can handle that, with a little guidance on the markdown.

There were a few things I didn't like or understand about the code, so, using it as a baseline, I rewrote a lot. Using some of the new ES6 features. In many cases, I realized that the original author Chris had made good choices and my code moved closer and closer to his! To be honest, many of my differences are more "to be different" and "see how they work" than from any compelling need.


  1. Markdown
    • CMS.js uses it's own short regex based Markdown parser, based upon Slimdown
      • note, there is an option to use another engine
    • I use Marked.js. Yes, larger bundles, Google Lighthouse complains a bit.
  2. Templates
    • CMS.js uses it's own short template engine and language, which relies ultimately on function().
    • I use ES6 Template literals. "Partials" are simply implemented as more functions you call. Ultimately, you code your templates in javascript, not a template language. IMO, one can better integrate css classes for styling. There are plusses and minuses to both. It did take some getting used to, but ultimately I liked it. Turing complete has advantages.
  3. Async
    • CMS.js uses callbacks
    • I use promises or, occasionally, async.
  4. Styling
    • CMS.js offers some flexibility with "themes"
    • I just use chota.css with a few modifications.
  5. Other
    • CMS.js uses XMLHttpRequest
    • I use fetch()
    • CMS.js offers a "Github mode", and probably does a better job on tags and search.


  1. Overall structure is very similar
  2. ES6 classes
  3. ES6 import / export

Other Additions I made

  1. I have an explicit "Gallery" type since many of our posts include multiple pictures.
    • there is also a "leitmotif" option to associate a single image with a post.
  2. There is a separate Carousel page to view all the pictures. That was fun to create.
  3. The markdown frontmatter can be either YAML (delineated by "===") or JSON (deliniated by "{" and "}").
  4. There was an attempt to make it more "pluggable" (like Metalsmith) that didn't really pan out. If this ever does gel this code might be worthy of a public github repository. For now its my own private thing.
  5. Basic dark mode support.

The result

Check it out:

So far, so good. My co-owners have been able to post content and pictures, with only a couple of glitches. They like it, and so do our visitors. That's the ost important thing.

I was concerned about performance. The rendering is performed each time a page is loaded. It seems to be just fine for us (see Google Lighthouse reports below). Mobile performance is hit partly by downloading the marked.js library, and mainly by resizing pictures "responsively". The accessibility rater complains about our text's colors. They look fine to me. I was also concerned about SEO, because most of the index.html page (<main></main>) is blank, and gets filled in later. But add enough <meta> tags and they seem happy. If this were a major site, hoping for thousands of hits a day, I'd be more concerned about SEO and performance.

Lighthouse Report (desktop)
Lighthouse Report (desktop)

Lighthouse Report (mobile)
Lighthouse Report (mobile)