StaPy

Static Site Generator

StaPy is a Static Site Generator. It works with Python without any additional package.

Download Source

Requirements

Requires Python 3.4 or newer on any operating system.

Installation

Create a project directory anywhere and download the last release from StaPy repository or from the link above.

mkdir stapy
cd stapy
wget https://codeberg.org/magentix/stapy/archive/last.tar.gz
tar zxvf last.tar.gz --strip 1
rm last.tar.gz

HTTP server

Run standalone HTTP server:

python3 server.py

On Windows 10 just double-click on the server.py file.

Then access the URL http://localhost:1985

Environments

Static files are generated in the web directory. This directory contains all the necessary environment directories (devel, prod...).

For the production, add a prod directory in the web directory. It will contain all pages and files you need to deploy (html, css, js, images...).

After you add a new environment, you must restart the server.

Route

When a page is open in the browser, the server search a json file in source/json directory. The name of the json file is the same as the URL path. Examples:

/                 : index.html.json
/hello.html       : hello.html.json
/hello/world.html : hello/world.html.json
/hello/world/     : hello/world/index.html.json

If the json file does not exist, a 404 error is sent.

Configuration

The json file contains all the data required for generate the page:

{
  "title": "Page title",
  "description": "Page description",
  "template": "template/default.html",
  "content": "page/index.html"
}

The template key is required.

Set the environment variables with the environment suffix:

{
  "url.local": "http://localhost:1985/",
  "url.prod": "https://www.example.com/"
}

The environment suffix must have the same name as your environment directory. For local rendering, the suffix is always "local".

A variable can have a default value:

{
  "my_text": "All environments display this text",
  "my_text.local": "Except the local with this"
}

A file named html.json in the source/json/default directory is used for the default html page configuration. It will be merged with the page's json file. This is useful for a global configuration.

default/html.json

{
  "title": "Default title",
  "template": "template/default.html"
}

index.html.json

{
  "title": "Home title",
  "content": "page/index.html"
}

default/html.json + index.html.json

{
  "title": "Home title",
  "template": "template/default.html",
  "content": "page/index.html"
}

You can add default config file for any file extensions you need:

The default/common.json config file is available for all pages (all extensions).

Note: the default config file is optional.

Tip: Add _page/ before the path to fetch json data.

http://localhost:1985/_page/index.html
http://localhost:1985/_page/hello.html

Template

The template file is the skeleton of the page:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
        <meta charset="utf-8">
        <title>{{ meta_title }}</title>
        <meta name="description" content="{{ meta_description }}" />
        <link rel="stylesheet" href="{{ url }}css/style.css" />
    </head>
    <body>
        <header>
            {% header %}
        </header>
        <main>
            {% content %}
        </main>
        <footer>
            {% footer %}
        </footer>
    </body>
</html>

Expressions

All variables in double curly braces {{ }} will be replaced with the text declared in the json file for the var.

All variables in curly brace percent {% %} will be replaced with the content of the file declared in the json file for the var.

Tip: set empty string for a content file variable in the json file to replace it with empty text.

Child block

Use specific json data for the child content with a + separator (spaces are required):

{% post + my-first-post.html %}

The json/my-first-post.html.json data will be accessible in the post template, with a $ before the var:

<a href="{{ url }}{{ $_path }}">{{ $post_title }}</a>

To loop json data with a query, use ~ as separator (spaces are required):

{% post ~ {key:value} {key:dir} {start:end} %}

Example:

{% post ~ tags:post date:desc 1:10 %}

This query retrieves the 10 first pages with post value in tags, sorted by date. The tags and date vars must be present in the json data of the pages:

{
  "date": "2022-01-01",
  "tags": ["post"]
}

The json data will be accessible in the post template, with a $ before the var.

Reserved variable

In any template, the _path var is reserved for the current page path:

{{ url }}{{ _path }} <!-- https://www.example.com/hello.html -->

Resources

All necessary resources like js, css or images are copied from the source/assets directory in all environment directories (e.g. web/prod).

Static files

The final static HTML files and resources are added or refreshed when the pages are opened in the browser. When /hello.html is open, the hello.html file is automatically generated in all environment directories (e.g. web/prod).

Crawler

The website can be regenerated with a crawler. StaPy gives a python crawler script in the tools directory.

python3 tools/crawler.py {delete} {copy} {crawl}

Launch crawler with no option perform delete, copy and crawl:

python3 tools/crawler.py

DELETE 200
PUT 200
HEAD 200 /index.html
HEAD 200 /hello.html
...

Deployment

If you are using an automated deployment tool like Netlify, Cloudflare Pages, Vercel or Render, configure the tool to deploy the environment directory from the git repository (e.g. web/prod).

To deploy with Github Pages, create a docs directory with a symlink from web/prod to docs. Commit and push the docs directory, then configure Github Pages to deploy docs.

Themes

Simple and minimal themes for StaPy: