Blog20 Static Site Generator
Dec 03, 2020
This is my personal static site generator, not intended to be used by anyone who isn't me. Feel free to use it if you want, just don't expect much in the way of documentation or tech support.
It is built using waf, all content is 100% statically generated, and the site uses no javascript (although individual pages could have javascript).
It uses python-markdown to render markdown content, which includes support for code hilighting via pygments. The site's custom CSS also includes light and dark mode variants using media selectors.
It also uses the css-html-js-minify project to shrink generated content, which actually results in some pretty decent space savings for CSS. The HTML minifier isn't used because it was breaking my styles and the space savings were negligible anyways.
Usage
Some basic instructions on how to use it. Assumes basic knowledge of Waf.
Installing dependencies
This tool requires Python 3 (untested on Python 2.x), and the following dependencies from pip:
- Markdown
- Pygments
- css-html-js-minify
- Pillow
- pygifsicle
Install them all as follows:
1 |
|
Note however that pygifsicle also requires you to have gifsicle installed system-wide.
Creating Pages
Example from About page:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
target
is the output name of the page (translates to About.html
in this example). The .md files in the source
attribute will automatically be compiled into HTML.
The page_template
feature will generate a page in the static output folder using the given template
and navmenu
.
template
must point to an html file which is to be populated with the compiled .md content and mamvmenu. A valid template requires two elements:
- A
div
with the id attribute "NavMenu" - A
article
with the id attribute "MainContent"
If template
or navmenu
are omitted, the environment variables tpl_main
and NavMenu
will be used.
NavMenu
must be a list of strings, where each entry is a named generator. If no matching generator is found, the link will just point to '#'. You can also use a Tuple to add a custom link.
Copyfiles feature
The copyfiles
feature string (used like page_template
in the above example) allows you to specify a copyfiles
attribute, where you can list source files that will be processed and copied to the static output directory. Processing depends on the file extension. The only processing done currently is that .css and .js files are passed through the minifier.
Automated image file conversions
You can also have waf automatically convert all of your images into a common format, as well as scale them down to a maximum size. In the example below, every image that passes through copyfiles will be converted to WebP and proportionally scaled down if any dimension exceeds 512 pixels. Additionally, gifs will be optimized using gifsicle:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
When writing a Markdown file, you need to be sure to link to the original image file, and the generator will automatically update the links to the newly generated files. For example:
1 2 3 |
|
That Markdown will be automatically converted to the following during compilation:
1 2 3 |
|
Creating Index Pages
An index page is like a folder which contains other pages. The About
example above only had one source file, but adding multiple source files will automatically convert it into an index page. This means that instead of a single About.html
file in the static output directory, there will be an About
folder that contains all of the compiled files from the source
attribute. Also note that the first file in the list will be named index.html
, so visting the folder will show the contents of that file only.
The index
feature string tells waf to generate a index.html
page (instead of using the first source entry) which contains a list of links to all of the other files in the folder. See the Blog example below:
1 2 3 4 5 6 7 8 |
|
Simply specifying "index" will achieve the desired result, but you can also customize the generated index page with the custom_index
attribute. This should be a .md file which includes the string "$items" somewhere. This will be substituted for the list of links to items.
For example:
1 2 3 4 5 |
|
Creating a Series of Pages
A series is like a linked list of individual pages. It's similar to an Index page, but additionally includes navigation links towards the bottom to go to the next/prev page. Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
This example defines an index page with a custom index (page_template
and index
feature strings). It also uses the series
feature string, and has all of the source files listed in the pages
attribute rather than the source
attribute.
This is because the series
feature will process the pages
list to build a navigation and other info, and then add those to the source attribute for regular processing into an index page. You could use ant_glob
to populate the pages, but doing it manually like in the example above allows you to control the ordering.
The example above uses the static_root
attribute to specify where in the static output folder this series should be placed. In this example, it's set to "Blog", so it will go into the Blog subfolder. Without the static_root
attribute, the series will be placed at the root of the static output folder. This is a problem if the source files for the series are located in a subfolder of another index page. When this occurs, the series will render as an item in the that index page, but the links to it won't work.
Nested Series
You can also have nested pages in your series by adding tabs to your ordered list of pages
. See the example below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The only thing this does is affect the way index pages are rendered. Nested items will be indented using CSS.
Markdown Metadata
You can add some metadata to your pages by prepending your markdown with a json string followed by exactly five hypens as shown below:
1 2 3 4 5 6 |
|
The title
attribute will be automatically added as a header to the top of the article, and to the title property of the window. You can omit the title, and a title will automatically be generated based on the filename. hyphens (-
) in the filename will be converted to spaces when rendering titles. If you want to add a hyphen to your title via the json metadata, you need to escape it with a \
.
Example:
1 2 3 4 5 6 |
|
The date
should be in the following custom format: YYYY-MM-DD/hh:mm:ss
. It will be automatically added as a subtitle under the title header, and shown on index pages.
date
can be omitted completely, or you can choose to omit the time only. Examples of valid date strings:
2020-12-03/13:30:54
2020-12-03/13:30
2020-12-03
OpenGraph Tags
The following keys will be used to generate opengraph tags if present in the metadata json:
Json Key | OpenGraph Tag |
---|---|
title | og:title * |
description | og:description |
image | og:description |
type | og:type |
url | og:url * |
locale | og:locale |
* Automatically generated if omitted
You can also manually override the tag values by using the OpenGraph tag as the key name. For example:
1 2 3 4 |
|
That will use the string Blog
when rendering the page/title bar, and Alex's Blog
as the OpenGraph title tag.
Build Options
You can use the following options during configuration to customize the build:
--no-gif-optimizer
disables all gif optimization tasks. This is useful when you need quick rebuilds, as optimizing gifs is slow--img-shrink-maximum
sets the maximum dimension when shrinking images. An image with a dimension larger than this will be proportionally shrunk--img-convert-format
sets the output format used when converting images. The default is "webp"--snd-convert-format
sets the output format used when converting sounds. The default is "mp3" (audio file conversions not currently implemented)
© Alejandro Ramallo 2024