The Linux Rain Linux General/Gaming News, Reviews and Tutorials

mkws - Static Site Generation With The Shell

By Andrew Powell, published 17/02/2021 in Reviews


Today I'm looking at something a little different. Rarely (or ever?) do I take a look at static website generators on here, but mkws is a bit of a special case.

mkws is a static site generator (SSG) created by Adrian Emil Grigore, written in nothing but the good old shell. No, not BASH, but sh. Well technically it includes a couple of minimal binaries, but we'll get to that in a moment.

So what does mkws promise? The home site's tagline simply reads - "A small, no bloat, minimalist static site generator using sh as a templating language."
And honestly, that sums it up as well as anything. mkws strives to be minimal, sane and yet thanks to the power of sh and standard Unix-y tools, very extensible and modifiable.

There's certainly no shortage of SSGs out there, and some of them are even written in BASH or otherwise some other shell language. What I believe sets mkws apart though, is that the templating part of it is done in shell, but the heavy processing is done by a small, extremely fast binary simply called pp, a pre-processor that runs any nested sh code in a given file.

What It Looks Like

Take the following example:

<!doctype html>
 <html lang=${LANG%%_*}>

 <head>

 <title>My website</title>

 <meta charset=${LANG##*.}>
 <meta name=viewport content='width=device-width'>

 <link rel=icon href=favicon.ico type=image/x-icon>
 <link rel=stylesheet
 href=s.css?$(lmt -f '%Y-%m-%dT%H:%M:%SZ' s.css | cut -d' ' -f1)>

 </head>

 <body>

 #!
 pp "$1"
 #!

 </body>

 </html>

The above is the stock standard main template file included in the mkws package. It's mostly HTML as you know it, but there's a few obvious shell bits and pieces such as $LANG and even a bit of code comprising well known commandline tools like cut (in that example, the author wrote in a way to automatically generate a timestamp for the external CSS stylesheet, to help with cache-busting).

Further down is where the magic happens - see the bit of code nested in between the #! lines? That's where the sh code takes place. You can put anything here you otherwise would in a shell script or at a command prompt. From there, you can pretty much do anything that your imagination or shell knowledge allows you to.

In this case the $1 being fed to pp is another template (eg. index.upphtml) by the main mkws program. That file could well have another call to pp nested inside it, and so on. pp will be essentially calling itself over and over, as much as you need. If you need a template file to do dynamic processing, pp will do it. As in the above example, it's not just within the #! blocks that sh code is processed, it will process inline variables and the likes too.

The "main" mkws script that pulls all this together? See here:

#!/bin/sh -e

usage() {
    >&2 printf "usage: %s url [path]\\n" "$(basename "$0")"
    exit 1
}

test $# -lt 1 && usage

srcdir=${2:-.}
sharedir=${MKWSTHEMEDIR:-"$srcdir"/share}
LANG=${LANG:-en_US.UTF-8}

if ! test -f "$srcdir"/index.upphtml
then
    >&2 printf "no index.upphtml file found\\n"
    exit 1
fi

echo "Making s.css"
pp "$sharedir"/s.uppcss "$1" > s.css

for t in "$srcdir"/*.upphtml
do
    echo "Making $(basename "${t%.upphtml}".html)"
    pp "$sharedir"/l.upphtml "$t" "$1" > \
        "$(basename "${t%.upphtml}".html)"
done

echo "Making sitemap.xml"
pp "$sharedir"/sitemap.uppxml "$1" > sitemap.xml

Out of the box, that's all there is to it.

So if you create a file called index.upphtml (the .upphtml extension is important, mkws looks for it as a template) with even just a basic content as thus:

<p>
#!
echo hello, world
#!
</p>

Then run (replacing example.com with whatever domain you want/need):

./bin/mkws https://example.com

In a split second, suddenly you have a nice new generated index.html with proper HTML and a simple 'hello, world' nested inside <p> tags. That's seriously all there is to it. And to create new pages you simply make another .upphtml file, eg. about.upphtml, add in whatever you need to that file and re-run the ./bin/mkws script and it does the rest.

It's very simple, but actually very powerful.

The Docs page neatly details all this better than I ever could so go check it out if you want to know more. Suffice to say, installation is just a matter of downloading the archive and extracting it. From there you can literally create your minimum required index.upphtml and away you go.

Go Forth And Tinker

As I said before, you're only limited by imagination and shell or Unix/Linux userland knowledge. You don't need to worry about getting a specific plugin or fighting the program to add specific features, mkws is fairly un-opinionated and the developer even encourages making modifications to the main script for your specific use case or website.

Just as a quick example, want Markdown? Just install smu (or your Markdown processor of choice) from your package manager, and inside your relevant *.upphtml file:

#!
    smu MyAwesomeFile.md
#!

Yay, we have Markdown parsing. Too easy, no?

Because it runs with /bin/sh, you will need to be aware of any "BASH-isms" you might have picked up. I certainly did, and in the process quickly learned how over reliant on BASH I had become. It's just a matter of educating one's self on the minor syntax differences or alternate ways of doing a certain thing, for example doing without BASH's brace expansions. I think it's worth learning to work with sh and trying to be a bit more POSIX compliant, especially for portability reasons, which the author of mkws clearly takes into account too.

One final, important note: A canny eye may have noticed in the examples above, attribute values in the HTML code are using either single quotation marks or none at all. This is important to not upset pp's internal sh processing. If you insist on using double quotation marks, they must be escaped, eg. \".

And that, friends, is basically it. Consult the Docs for the full rundown, including the file/folder hierarchy. It's one page, rather than a whole slew of documents, which again speaks to the simplicity of mkws.

Personally, I like mkws a lot. I am actually fairly picky when it comes to choosing a static website generator, because on the one hand I like pure simplicity and easy to reason-about code, but on the other hand some SSGs can be too limiting while still not being easy enough to customize. mkws for mine is both small and minimal, but not remotely limiting, and packs a punch because sh works surprisingly well as a templating language.



About the author

Andrew Powell is the editor and owner of The Linux Rain who loves all things Linux, gaming and everything in between.

Tags: reviews static-site-generators shell commandline
blog comments powered by Disqus