Statiq Charge: Building Static Sites with Statiq & Python

by Marcin Giziński, CIO

In the ever-evolving world of web development, it's easy to get lost in the plethora of frameworks, libraries, and tools available. Yet, there's something to be said for the power and simplicity of static HTML. Let's explore when and why one might choose static HTML over a more complex framework.

No Frameworks Attached

Static HTML remains a powerful tool in the web developer's arsenal, especially for simpler projects. While frameworks offer robust features and scalability, it's essential to evaluate the actual needs of a project before choosing the right approach. Embracing the strengths of static sites, while being aware of their limitations, can lead to a faster, more reliable, and potentially more secure web experience.

When to Use Static HTML

  • Simple Websites:

    For sites that have a handful of pages with mostly static content, such as personal portfolios, blogs, and small business websites.

  • Performance:

    A static page inherently has fewer elements to process, potentially leading to faster load times.

  • Limited Resources:

    When working on a project with minimal budget or manpower, avoiding the learning curve of a framework might be beneficial.

  • Teaching Beginners:

    For newcomers to web development, starting with the basics provides a solid foundation.

Advantages of Static HTML:

  • Speed:

    Static websites, by nature, are faster as there's no database to query or server-side processing needed before sending the page to the user.

  • Simplicity

    No need to manage the complexities or dependencies of a framework.

  • Reliability

    Fewer components mean fewer things can break.

  • Cost-Effective

    Many hosting providers offer low-cost or even free hosting for static sites. Plus, they're less resource-intensive, which can translate to savings.

  • Version Control

    With platforms like GitHub, it's easy to manage versions of static sites and collaborate with others.

Disadvantages of Static HTML

  • Scalability Issues

    For larger sites or web applications, manually managing multiple HTML files can be cumbersome.

  • Lack of Dynamic Content

    To introduce interactivity or real-time data, you'd need to resort to adding JavaScript, which somewhat defeats the "pure static" concept.

  • No CMS

    Non-tech-savvy users might find it challenging to update content without a Content Management System.

  • Repetitive Tasks

    Elements that appear on multiple pages, like headers and footers, must be updated individually unless using a templating system.

Security Implications

While one might assume that static sites are inherently more secure (given the absence of a database or server-side scripts), it's not quite that simple.

Pros:

  • Fewer Vulnerabilities

    No databases or server-side scripts mean fewer avenues for common attacks like SQL injection.

  • Immutable

    Content isn't changed unless the developer explicitly changes and redeploys it.

Cons:

  • Client-Side Scripts

    If you rely on JavaScript for added functionality, vulnerabilities in the code can still pose risks.

  • Third-Party Integrations

    Incorporating third-party tools or plugins can introduce security issues if not properly vetted.

Harness the hiss - Tutorial

Before diving in, it's worth noting this tutorial assumes familiarity with Python basics, including the use of virtual environments and pip.

Installation

To get started with Statiq, first, install it using pip:

pip install statiq

Next, within your project directory, create a pages directory and an initial index.py file:

mkdir pages
cd pages
touch index.py

Open the newly created index.py in your preferred editor and add the following content:

# pages/index.py
from statiq import Page

def page():
    return Page(
        data={
            "title": "Hello World"
         }
    )

Then, create a templates directory and an index.html file within it:

mkdir templates
touch templates/index.html

Edit templates/index.html to include:

{% extends "base.html" %}
{% block content %}
<h1>{{ title }}</h1>
{% endblock %}

Building Your Website

With your pages and templates set up, you're ready to build your website:

statiq build

Congratulations! You've just created a simple static website. The generated code can be found in the build/ directory. To view your website locally, serve it using Python's HTTP server:

python -m http.server --directory build

Navigate to http://localhost:8000 in your web browser, or use the following command to open the site automatically (on Mac and Linux systems):

open http://localhost:8000

Creating Dynamic Pages with Statiq

Dynamic pages in Statiq are generated based on path parameters, offering a way to create content that adapts to the given context, such as blog posts or product pages. This capability allows for a more flexible site structure, where content can be dynamically served based on user interaction or specific URL paths.

Defining Path Parameters

To create a dynamic page, Statiq uses path parameters defined within square brackets in the filename or folder name. Here's how you can structure your project to include dynamic content:

  • pages/[post].py: This will generate a page for each post, accessible through a unique slug (e.g., build/some-post-slug.html).

  • pages/[category]/index.py: This sets up a structure for category pages, where each category's main page can be accessed (e.g., build/some-category/index.html).

Setting Up Templates

The `templates` folder should mirror the structure of the `pages` folder to ensure each dynamic page is rendered with the correct template. For instance:

  • templates/index.html: The main site template.

  • templates/[post].html: A template for individual posts.

  • templates/[category]/index.html: A template for category landing pages.

Creating a Page File

Each .py file that defines a page should contain a page() method that returns a Page object. This object includes all the necessary details to render the page, such as title, description, and content. Here's a basic example:

from statiq import Pagedef page() -> Page:
    return Page(
        data={
            "title": "Welcome to Statiq",
            "description": "Statiq is a static site generator",
            "content": "Hello world!",
        }
    )

Utilizing Path Parameters

Path parameters are crucial for generating dynamic content. They are defined as a list of dictionaries passed to the Page object, which then utilizes these parameters to render different content based on the URL.

from statiq import Page

def page() -> Page:
    return Page(
        data={
            "title": "Dynamic Content",
            "description": "Example of a dynamic page",
            "content": "Content based on path parameters",
        },
        path_parameters=[
            {"post": "some-post-slug"},
            {"category": "some-category"}
        ]
    )

Expanding Path Parameters in Data and Head Properties

For routes utilizing path parameters, these parameters are expanded and passed as keyword arguments to the data and head properties, allowing for customized rendering based on the URL.

Example with multiple path parameters:

from statiq import Page

def get_data(**kwargs):
    post = kwargs.get("post")
    # Dynamic data fetching based on the post parameter
    return some_data.json()def get_head(**kwargs):
    post = kwargs.get("post")
    return [
        f"<title>{post} - Dynamic Page</title>",
        {"tag": "meta", "attributes": {"name": "description", "content": post}}
    ]

def page() -> Page:
    path_parameters = get_path_parameters()
    return Page(
        data=get_data,
        head=get_head,
        path_parameters=path_parameters,
    )

The template_path Property

To specify a custom template for a dynamic page, use the template_path property within the Page object. If not defined, Statiq defaults to using index.html.

from statiq import Page

def page() -> Page:
    return Page(
        data={"title": "Custom Template Page"},
        template_path="custom.html",
    )

By following these steps, you can leverage Statiq to create dynamic, content-rich pages that respond to user interactions and display content based on specific criteria, enhancing the overall user experience on your static website.

Including Static Content

Incorporating static assets like images, JavaScript, and CSS into your static website is a common requirement. Statiq simplifies this process by efficiently handling the parsing and copying of these files. Let's dive into how you can manage static files in your Statiq project, using `static.png` as an example file.

Setting Up Static File Management

Configure Static Paths

First, you'll need to specify where your static files are located and where they should be copied to. This is done in the config.py file of your Statiq project. Open or create your `config.py` and add the following properties:

# config.py
STATIC_PATHS = [
    {"path": "src"}  # Directory where your static files are located
]
STATIC_OUTPUT_PATH = "output"  # Destination directory for the static files

Customize File Selection (Optional)

If you want to filter which files are copied based on their type or any other criteria, you can use the optional regex property. For example, to only include HTML files, your STATIC_PATHS configuration might look like this:

STATIC_PATHS = [
    {
        "path": "src",
        "regex": r"(.*)\.html$",
    }
]

However, if you're including an image file like `static.png`, you don't need to apply such a filter.

Copying Static Files

With your static paths configured, you're now ready to copy these files to the designated output directory. This is done using a simple command:

statiq static copy

This command tells Statiq to process the directories and files specified in STATIC_PATHS and copy them to the STATIC_OUTPUT_PATH. For instance, if static.png is located in your src directory, it will be copied to the output directory, maintaining the directory structure.

Example Use Case

Imagine you have a file named `static.png` in your `src/images` folder. To ensure it gets copied to your output directory, make sure your `config.py` file looks something like this:

# config.py
STATIC_PATHS = [
    {"path": "src"}  # This includes all files within the src directory
]
STATIC_OUTPUT_PATH = "output"  # static.png will be copied to output/images

After running statiq static copy, static.png will be available in output/images, ready to be served alongside your static site.

Conclusion

Managing static files in Statiq is straightforward, thanks to its flexible configuration options. By setting up STATIC_PATHS and STATIC_OUTPUT_PATH, you can easily include assets like static.png in your projects, enhancing the visual and functional aspects of your static website. This process, combined with Statiq's efficiency in generating static pages, provides a robust foundation for developing fast, secure, and visually appealing websites.

Sponsored by Folx, Statiq emerges as a response to the Python community's need for a modern static website generator, offering a robust alternative to popular JavaScript solutions like Next.js and Vue.js, and marking a significant step towards enriching the Python ecosystem with cutting-edge web development tools

Tell us about your project

Our offices

  • Warsaw
    Puławska 39/40
    02-508 Warsaw
  • Warsaw
    Bohaterów Września 9/104
    00-389 Warsaw