Under the hood
Hello World!
This short sentence is usually used by programmers in the very first program they wrote. It does not feel enough for a first post, so I decided to briefly describe the technical solution for this blog.
How it begins
Some time ago I've decided that I want to start my technical blog. Unfortunately for me, I am a little bit idealist, so I cannot decide for long what should power my blog.
Hosted platforms like Medium or WordPress are definitely not for me, because I would like to have full control of my website.
Static site generator seems like a perfect solution to me, blog does not require any dynamic content. But somehow I do not like Jekyll which is the default solution for Github Pages.
I know that I want something simpler, much simpler.
Solution
I came up with the simplest solution which does not require writing pure HTML. Own static site generator written in node.js
Posts are written in Markdown and converted to HTML using markdown-it
const nunjucks = require('nunjucks')
const md= require('markdown-it')()
const meta = require('markdown-it-meta')
const title = require('markdown-it-title')
const prism = require('markdown-it-prism')
const include = require('markdown-it-include')
const fs = require('fs')
const inputFile = process.argv[2]
const outputFile = process.argv[3]
const env = new nunjucks.Environment(new nunjucks.FileSystemLoader(''))
md.use(meta)
md.use(prism)
md.use(title)
md.use(include)
const src = fs.readFileSync(inputFile, "utf8")
const ctx = {}
const contentHtml = md.render(src, ctx)
const html = env.render('src/html/post.njk', {
content: contentHtml,
title: ctx.title,
meta: md.meta
})
fs.writeFileSync(outputFile, html)
All .njk
files are converted to HTML using nunjucks.
For example, this is how index.html
page is generated
const nunjucks = require('nunjucks')
const fs = require('fs')
const env = new nunjucks.Environment(new nunjucks.FileSystemLoader('./'))
const inputFile = process.argv[2]
const outputFile = process.argv[3]
const html = env.render(inputFile)
fs.writeFileSync(outputFile, html)
Sass sources are also converted using simple javascript
const sass = require('sass')
const fs = require('fs')
const inputFile = process.argv[2]
const outputFile = process.argv[3]
const result = sass.renderSync({ file: inputFile })
fs.writeFileSync(outputFile, result.css)
And finally, all together is glued up by good old make
PAGES_SRC=$(wildcard *.njk)
PAGES=$(patsubst %.njk, target/%.html, $(PAGES_SRC))
POSTS_SRC=$(filter-out README.md, $(wildcard *.md))
POSTS=$(patsubst %.md, target/%.html, $(POSTS_SRC))
all : target $(PAGES) $(POSTS) target/style.css target/posts.html target/CNAME target/.nojekyll
.PHONY: all
target/%.html : %.md
npm run post $< $@
target/%.html : %.njk
npm run page $< $@
target/style.css : src/sass/*.sass
npm run css src/sass/main.sass $@
target/posts.html : $(POSTS_SRC)
npm run posts ./ $@
target/CNAME : CNAME
cp $< $@
target/.nojekyll :
touch $@
target :
mkdir target
clean:
rm -rf target
.PHONY: clean
Hosting & CI
Since Github Pages by default only supports Jekyll or static files,
I've used Github Actions to automatically generate static files on any changes to master
branch.
name: Build and Publish
on:
push:
branches: [ master ]
jobs:
build-and-publish :
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
- name: Install and Build 🔧
run: |
npm install
make
- name: Publish 🚀
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: public
folder: target
Source code
Since this blog is currently hosted on Github Pages, all source code is publicly available here.