Blockable is a free, open source, and simple static site generator written in python. The philosophy behind blockable is that many web developers use the same snippets of HTML repeatedly, but with different content. We believe snippets like these should be made into "blocks" which can be reused within a website or across multiple websites to ease the development process and save time.
In our experience many websites that rely on dynamically generated pages do not require completely dynamic content, which is unfortunate because dynamic CMss like Wordpress and Drupal are the most popular and will most likely unnecisarily extend loading times by causing the server to execute PHP and query an SQL database on every page load.
Why not just use a preexisting static site generator like Hugo or Jekyll or a templating engine like Jinja?
The two main reasons that we chose not to stick to an existing tool were as follows:
- We want to focus on reusing blocks of code so that websites can quickly be assembled from pieces of other websites. This saves development time, and encourages the sharing of code.
- We want to generate the site using a complete scripting language, in this case, Python. This allows the creation of sites to be very simple, or very complex, depending on the needs of the user. This also prevents developers from having to learn particular syntax for a program, and instead learn Python which is very common and reusable.
Python is a modern scripting language that is commonly known and easy to learn. Python will allow web developers new to blockable to simply return HTML, but will also allow developers familiar with Python to utilize it to save time.
This is the terminology that will be used in Blockable and its documentation. Be certain to consult this list or there may be confusion of terms as it may differ from other tools.
A directory generated by Blockable, containing all of the page files and asset files.
A file such as an image, a font, a stylesheet, or a javascript file.
A HTML file. Its looks are determined by its content file.
A JSON file generated by your CMS (Such as Netilfy) stored in the data folder. Each page has its own associated with it which specifies the layout as well as the content to fill into the layout.
A directory that contains a Python file capable of generating HTML, as well as any required asset such as a stylesheet, or file for the CMS in use if required. A block or a layout is an example of this.
A template used to generate a page which may contain a block. Layouts can be unique to a page or used by multiple.
A template used in a layout or another block.
Ways of organizing pages. There are two types:
- data-based collections
- layout-based collections
A collection where each page has same layout but with unique content.
A collection where each page has a unique layout and unique content.
Blockable is still a work in progress (see goals for more information), however in its current state, Blockable is designed to work like so:
When creating a website, there should be three primary folders: blocks, layouts, assets, and static. The assets folder is a folder for organizing content to be imported by blockable. The static folder is a folder for assets to be copied to the web root as it during complication. The blocks and layouts folder mimic each other in that each folder should contain a folder for each block/layout you want to create. These folders should then contain an index.py, a stylesheet.css and javascript.js if necessary, and a fields.json (more on this later).
index.py should define one main function called main(). This function should accept one variable (which will contain a dictionary of all the data requested in fields.json), and it should return a string of the html for that template. When writing your templates, you should make use of the blockable.blocks module which contains every block you defined in your blocks folder accessible by the name of the folder:
from blockable import blocks
blocks.nav_bar(data["nav_bar"])
To include stylesheets, javascript, and images within your program, developers should import the load_css, load_js, load_img functions from blockable:
from blockable import load_css, load_js
These functions accepts a path to an asset from your root blockable directory and returns a tag for that final asset:
site_stylesheet = load_css("assets/css/stylesheet.css")
layout_js = load_js("layouts/homepage/javascript.js")
logo = load_css("assets/images/logo.png")
In order to keep your site csp compliment, developers should also make use of the save_css function:
from blockable import save_css
save_css accepts a string of css and returns a style tag for the newly created stylesheet:
custom_css = save_css("""
.my_class {
color: black;
}
""")
Blockable also has a move_asset function which accepts a path to any asset from your root blockable directory and moves it to the web folder (placing it in an 'asset' folder). It then returns a URL to that final asset
right_arrow_src = move_asset("blocks/slider/right_arrow.svg")
Currently Blockable only supports Netlify as a CMS although support for more CMSs is planned in the future. In order to use Netlify, developers should create a config.json file and fill it out like a normal config.yml for Netlify (See Netlify documentation for information). The only difference is that when it comes to defining collections.
File-based collections (or layout-based collections) are accomplished by defining the collection like normal, except for the "files" section where developers should add the following dictionary into each file instead of just adding fields:
import (the location of the file you'd like to import such as "layouts/homepage")
name (the unique name of this import)
label (the non unique label of this import)
Folder-based collections (or data-based collections) are created in a similar way except you replace the "files" key with an import one pointing to the collections layout.
Next place a fields.json file in every template folder. This file should contain a list of each Netlify field for that template and, if necessary, the above import dictionary for any extra templates used.
For settings pages, you can create a new collection and set the files to be imported blocks. Developers can then use the get_page function to access any page data. Develoeprs can also use the get_pages function to get a list of pages. The function also supports the optional paratmers of a sort key which will sort the pages based on a field value for the page and a reverse key which reverse the sort:
from blockable import get_page, get_pages
blog_list = get_pages("blog", sort="date", reverse=True)
for blog in blog_list:
blog_data = get_page(blog)
title = blog_data["title"]
Finally, developers can run
python -m blockable <source> -M
to generate a working config.yml for Netlify to use.
To compile your site into html, simply run
python -m blockable [source] [output]
Where source is the directory of your blockable instance and output is where you would like to send the output. Note that since blockable uses rsync, this output can be a non-local destination (i.e. user@website.com:/opt/www/website.com). When compiling for a finished product, you should also enable the "--final (-f)" flag which will optimize the site by creating multiple copies of every image for srcset, converting images to webp, etc.