How to make an markdown(md) blog!

jan 18 2023 by syonfox


Sometime we just want to write and that is why markdown is so popular. You can just type what you want in plane text and not worry about the details of formatting. A beautiful page is render on the fly or in the build step. And everything you could need is only a few keystrokes away.

sudo apt install featherpad npm git
mkdir blog
cd blog
npm init

mkdir public
mkdir posts

featherpad package.json

You will want to edit you package json to add these dependencies and then npm install

  "dependencies": {
    "cheerio": "^1.0.0-rc.12",
    "markdown-it-anchor": "^8.6.6",
    "markdown-it-toc-done-right": "^4.2.0"

featherpad md2html.js

After wi install the above dependancies with npm install we can write our script to convert our blog posts to a nice pretty html page.

const fs = require('fs');
const path = require('path');
const md = require("markdown-it")({
  html: true,
  xhtmlOut: true,
  typographer: false,
  quotes: '“”‘’',
}).use(require("markdown-it-anchor"), {
  // permalink: true,
  // permalinkBefore: false,
  // permalinkSymbol: '§'

const cheerio = require('cheerio');
if(process.argv.length < 3) {
	console.log("Usage: node md2html.js [dest_dir]");

let inputFile = process.argv[2];
let outputFile = path.parse(inputFile).name + '.html';
let dest =  process.argv[3]

if(dest) { // if dest specified join path to it 
	outputFile = path.join(dest, outputFile);
console.log("Rendering: ", inputFile, " -> ", outputFile);
fs.readFile(inputFile, 'utf8', (err, data) => {
  if (err) {
  } else {
    // Render the Markdown to HTML
    const html = md.render(data);

    // Read the template HTML file
    fs.readFile('template.html', 'utf8', (err, template) => {
      if (err) {
      } else {
        // Load the template HTML into cheerio
        const $ = cheerio.load(template);

        // Inject the contents of the Markdown file into the body of the template

        // Write the modified HTML to a file
        fs.writeFile(outputFile, $.html(), 'utf8', (err) => {
          if (err) {
          } else {
            console.log(`HTML file ${outputFile} generated successfully`);

featherpad template.html

Notice that the aboce script injects the post into this template in the div with class post using cheerio!

<!doctype html>
    <title>SGOL Post</title>
	<link rel="stylesheet" href="">
 		<a href="./index.html">Index</a>
  	<div class="post"></div>

And that's it time to write you shiny new blog post and deploy the public folder to a web server of your choice.


  1. featherpad posts/
  2. node md2html.js posts/ ./public
  3. firefox public/my_new_post.html