gnrt - static site generator
2020-06-13
Although there are already plenty of static site generators available, it is quite hard to find one which is fast, lightweight, minimalist, easy to use and which simply generates HTML files from structured content, using templates.
Enter gnrt, a static site generator written in Python 3.
Using gnrt
By default, gnrt does not need any configuration.
You write Markdown content files in the content folder, execute gnrt, and it will output HTML files in the public folder.
$ cat content/index.md The body content here. $ gnrt Generated 0 includes Generated 1 targets $ cat public/index.html <p>The body content here.</p>
Let's add some structure by creating a Jinja2 template in the templates folder and pointing to it in the content frontmatter.
$ cat templates/page.j2
<html>
<body>
{{ body }}
</body>
</html>
$ cat content/index.md --- template: page.j2 --- The body content here.
$ gnrt Generated 0 includes Generated 1 targets $ cat public/index.html <html> <body> <p>The body content here.</p> </body> </html>
Since it is not very convenient to point to the same template each time you create new content, let's create a configuration file and add some defaults.
$ cat config.yml defaults: template: page.j2
We can then remove the template key from the frontmatter, and re-generate.
$ gnrt Generated 0 includes Generated 1 targets
$ cat public/index.html <html> <body> <p>The body content here.</p> </body> </html>
Lists
Menus can be generated using the concept of lists.
$ cat config.yml
defaults:
template: page.j2
lists:
menu:
template: nav.j2
$ cat templates/nav.j2
<ul>
{% for key, value in items %}
<li><a href="{{ value.link }}">{{ value.title }}</a></li>
{% endfor %}
</ul>
Let's say that we created an About page (content/about.md), and re-generate.
$ gnrt Generated 1 includes Generated 2 targets
The menu has been generated as includes/menu.html.
$ cat includes/menu.html <ul> <li><a href="/about.html">about</a></li> <li><a href="/index.html">index</a></li> </ul>
This menu can then be included in the generated output, by adding {{ menu }} somewhere in the page template, and by pointing to it either in the frontmatter, or easier, in the configuration file.
$ cat config.yml
defaults:
template: page.j2
menu: includes/menu.html
lists:
menu:
template: nav.j2
$ cat templates/page.j2
<html>
<body>
{{ menu }}
{{ body }}
</body>
</html>
Lists can be filtered (e.g. by category of content), sorted (e.g. by publication date) and limited to a certain number of items.
Example:
nav-latest-articles:
template: nav-article.j2
filter:
key: category
value: article
sort: published
reverse: true
limit: 2
The target key allows to specify where the generated list will be saved; this makes it possible to generate a RSS feed for instance:
rss:
filter:
key: category
value: article
sort: published
reverse: true
template: rss.j2
target: public/rss.xml
Data access
The whole website dataset and configuration is available in the templates and markdown content through the {{ data }} and {{ config }} keys.
$ cat content/index.md
---
id: home
title: Home
link: /
---
Welcome to the homepage.
Check the [about]({{ data.about.link }}) page or read the [articles]({{ data.articles.link }}) !
Fast and lightweight
gnrt 0.1.1 contains around 100 lines of Python code and is feature complete, at least for my needs - I use it to generate this website.
On a decent computer, it generates 1000 files (containing random text) in less than 1 second.
$ find content/ -type f | wc -l 1000 $ find content/ -type d | wc -l 51 $ time gnrt Generated 0 includes Generated 1000 targets real 0m0,612s user 0m0,574s sys 0m0,032s
Open source
gnrt is available on GitHub under the MIT license and can be installed via:
pip install gnrt
There is an example website implementation in the repository.
Last updated: 2022-03-20