simpet

Bob, a static blog generator

The blog engine

Starting from my markdown AWK parser, which was litterally done to achieve this blog engine, I've added an extra layer to turn it into a statis blog generator

Of course the parser is only one of the several components required for a blog generator, but I shall start from the beginning.

Initially I wanted to blog for me, and as described here, it was to mostly talk about tech.

The desire to make everything from scratch and reinvent the wheel is very strong, but we'll see how this evolve in the future.

Now that I have my markdown to HTML converter I don't lack much to turn in into `bob` my blog generator.

the boilerplate

After thinking about it, I did want to rely on git to store my drafts and posts, and have a CI listening to my blog repository that would do all the publishing work on the actual webserver. Hence the need for a self hosted git instance, and CI (reinventing the wheel I said).

Maybe I shall post about `gitea` and `drone CI` later on.

For this to happend, `bob` shall be a simple CLI, and screw it, a docker image as well.

I also wanted to only handle the markdown file, and let the html build itself.

I came up with a very simple folder architecture :

The idea is as simple as it gets : I write my drafts in the folder of the same name, when I want to publish them, I simply move them into the `published` subfolder and `bob` and the CI handle the rest.

But the markdown converter does not create a full html page, so here comes the need for boilerplating :

I made an `index.html` template, for the home page, and a `post.html` one, for the actual articles.

Once again this is very simple : the post page template's body looks like this :


    

simpet

{{article}}

and I use `awk` to replace `{{article}}` with the actual content of the posts, like so :

publish_one()
{ 
    # Storing the path of the post/article to publish 
    # The path is supposed to have this format "./drafts/published/
.* article_path=$1
    # from the relative path, only retrieving the name of the article (without file extension)
    article_name=$(echo $article_path | cut -d '/' -f 4 | cut -d '.' -f 1)

    # Convert the markdown draft into an html article and storing it locally
    post=$(awk -f ${BOB_LIB}/markdown.awk ./$article_path)

    # Retrieving the html article template
    template="${BOB_LIB}/template/post.html"

    # Escaping the & for next step to not confuse awk
    escaped_post=$(echo "$post" | sed 's/&/\{{article}}/g')

    # In the template, replacing the string {{article}} by the actual content parsed above
    awk -v content="$escaped_post" '{gsub(/\{\{article\}\}/, content); print}' "$template" > "./posts/$article_name.html"
}

The home page template is similar :


    

simpet

{{articles}}

and updated this way :

update_index()
{
    # Listing all posts and making an html list (with there link) out of them
    posts=$(ls -t ./posts | awk '
        BEGIN {
            print "
    " } { ref=$0 gsub(".html","",ref) gsub(/[_-]/, " ", ref) print "
  • " ref "
  • " } END { print "
" }')
    # retrieving the template for the index.html
    template="${BOB_LIB}/template/index.html"

    # replacing {{articles}} in the template with the actual list of articles from above
    awk -v content="$posts" '{gsub(/{{articles}}/, content); print}' "$template" > "./index.html"

}

Whenever an new article is added or removed of the `drafts/published` folder, the `update_index()` will adjust the home page, because call by this function :

publish_all()
{
    # List all drafts to be published
    published=$(ls -1 ./drafts/published)

    # turning it into an array
    published_array=($published)
    
    # Remove all html articles in case a previously published one was removed
    rm ./posts/*.html
    
    # Publish them one by one (ie turning md into html)
    for file in "${published_array[@]}"; do
        publish_one ./drafts/published/$file
    done

    # updating the index.html as new articles are supposedly present and some may be removed
    update_index
}

which basically only reads the ready to be published posts and turn them into an html file, using the template, and then update the `index.html`

That's it !

To sum up

I've made a very simple, not very customisable static blog generator, mostly using awk. It clearly is not optimized as it regenerated all the articles everytime, but awk is quite efficient, and for a few posts, I don't think it really matters.

The real benefit is that I only handle markdown files, the CI and `bob` do the rest...

Also, a statis site is blazing fast as loading in the browser, and since I do not use images (yet) nor javascript, I get a very very fast blog.

To be continued...