![Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility](https://cdn.sanity.io/images/cgdhsj6q/production/97774ea8c88cc8f4bed2766c31994ebc38116948-1664x1366.png?w=400&fit=max&auto=format)
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Statiq is a powerful Python framework designed to simplify the process of generating static websites based on folder structure. Whether you're a developer or a content creator, Statiq provides the tools you need to build beautiful, fast, and secure websites.
templates
to tailor your site's appearance.filters
, and middleware (coming soon)
to process and modify your content.cli
to manage your projects efficiently.pip
.
pip install statiq
statiq init demo
statiq build
python -m http.server --directory build
You need to create two folders to start using Statiq: pages
and templates
. The pages
folder contains all the structure of your website, and the templates
folder contains all the templates used to render your content.
Page
A page is a python file that contains a page()
method.
The name of the folder will be used as the URL of the page.
For example, the about.py
folder will be rendered as https://example.com/about.html
,
index.py
will be rendered as https://example.com/
, and blog/post.py
will be rendered as https://example.com/blog/post.html
.
Template
A template is a html file that utilizing Jinja2 syntax. You can use the {{ content }}
tag to render the content of the page.
pages/
folder structureSimple static pages will be generated based on the structure of the directory and the names of the files. For example, the following structure:
pages/index.py
pages/about-us.py
pages/about/index.py
will produce the given output:
build/index.html
build/about-us.html
build/about/index.html
Dynamic pages are pages that are generated based on the path parameters
. To define a path parameter
for a given route you need to put the .py filename or a folder name in square brackets
For example, the following structure:
pages/[post].py
pages/[category]/index.py
will produce the given output:
build/some-post-slug.html
build/other-post-slug.html
build/some-category/index.html
templates/
folder structureThe templates folder should have the same structure as the pages/
folder. You can override the template path, for more details see the Creating a page file section.
pages/index.py
pages/[post].py
pages/[category]/index.py
Should have the corresponding templates:
templates/index.html
templates/[post].html
templates/[category]/index.html
A .py file defining a page should contain a page()
method. The method should return a Page
object.
from statiq import Page
def page() -> Page:
return Page(
data={
"title": "Welcome to Statiq",
"description": "Statiq is a static site generator",
"content": "Hello world!",
},
head=[
"<title>Welcome to Statiq</title>",
{
"tag": "meta",
"attrs": {"name": "description", "content": "Statiq is a static site generator"},
}
],
)
For more details about using the Page
object, see the Page Object section.
The Page
object is used to define the content of the page. It has the following properties:
dictionary
or a Callable
containing the data that will be passed to the template.List
or a Callable
containing the data that will be passed to the template.list
of dictionaries
or a Callable
containing the data that will be used to replace the path parameters
in the route.string
containing the path to the template that will be used to render the page.data
propertyYou can define an object or a callable that returns an object. This will be passed to the template
def page() -> Page:
return Page(
data={
"title": "Welcome to Statiq",
"description": "Statiq is a static site generator",
"content": "Hello world!",
},
)
or using a callable
def get_data():
# do some mojo
some_data = requests.get("https://example.com/api")
return some_data.json()
def page() -> Page:
return Page(
data=get_data,
)
head
propertyYou can define a list of strings or dictionaries that will be used to generate the head
section of the page. This can be also a List
or a Callable
This will only work when your template extends the base.html
template. Otherwise you need to handle it yourself.
def my_head()
return [
# You can use a string
"<title>Welcome to Statiq</title>",
# or a dictionary with the given structure
{
"tag": "meta",
"attributes": {"name": "description", "content": "Statiq is a static site generator"},
}
]
def get_data():
# do some mojo
some_data = requests.get("https://example.com/api")
return some_data.json()
def page() -> Page:
return Page(
data=get_data,
head=my_head,
)
path_parameters
propertyThe path_parameters
property is used to define the path parameters
for the given page. It should be a list of dictionaries.
The object should be a List
containing dictionaries
with all the path parameters
that will be used to generate the page.
# /pages/[post].py
def page() -> Page:
return Page(
data={
"title": "Welcome to Statiq",
"description": "Statiq is a static site generator",
"content": "Hello world!",
},
path_parameters=[
{"post": "some-post-slug"},
{"post": "other-post-slug"},
],
)
path parameters
to data
and head
propertiesFor routes that utilize path parameters
they will be expanded and passed as a keyword argument to the data
and head
properties.
# /pages/[post].py
def get_path_parameters():
return [
{"post": "some-post-slug"},
{"post": "other-post-slug"},
]
def get_data(**kwargs):
post = kwargs.get("post")
# do some mojo
some_data = requests.get(f"https://example.com/api/{post}")
return some_data.json()
def get_head(**kwargs):
post = kwargs.get("post")
return [
# You can use a string
f"<title>{post}</title>",
# or a dictionary with the given structure
{
"tag": "meta",
"attributes": {"name": "description", "content": post},
}
]
def page() -> Page:
return Page(
data=get_data,
head=get_head,
path_parameters=get_path_parameters,
)
path parameters
# /pages/[category]/[post].py
def get_path_parameters():
return [
{"category": "some-category", "post": "some-post-slug"},
{"category": "other-category", "post": "other-post-slug"},
]
def get_data(**kwargs):
category = kwargs.get("category")
post = kwargs.get("post")
# do some mojo
some_data = requests.get(f"https://example.com/api/{category}/{post}")
return some_data.json()
def get_head(**kwargs):
category = kwargs.get("category")
post = kwargs.get("post")
return [
# You can use a string
f"<title>{category} - {post}</title>",
# or a dictionary with the given structure
{
"tag": "meta",
"attributes": {"name": "description", "content": post},
}
]
def page() -> Page:
return Page(
data=get_data,
head=get_head,
path_parameters=get_path_parameters,
)
template_path
propertyThe template_path
property is used to define the path to the template that will be used to render the page. If the property is not defined the page will be rendered using the index.html
template.
def page() -> Page:
return Page(
data={
"title": "Welcome to Statiq",
"description": "Statiq is a static site generator",
"content": "Hello world!",
},
template_path="custom.html",
)
To add a custom configuration to your project you need to create a config.py
file in the root of your project.
To add your own custom template filters you need to define a FILTERS
dictionary in your config.py
file. The key of the dictionary will be the name of the filter and the value should be a callable.
# config.py
from my_filters import my_filter, my_other_filter
FILTERS = {
"my_filter": my_filter,
"my_other_filter": my_other_filter,
}
To add global variables to your templates you need to define a GLOBALS
dictionary in your config.py
file. The key of the dictionary will be the name of the variable and the value can be an object or a callable.
# config.py
GLOBALS = {
"my_global": "some value",
"my_other_global": lambda: "some other value",
}
Statiq supports plugins that can be used to extend the functionality of the framework. To add a plugin you need to define a PLUGINS
list in your config.py
file.
Statiq provides an auxiliary class PluginBase
that can be used to create plugins.
Each plugin can have six methods which are called during different steps of the build process.
Every pre_*
method has access to path parameters
passed as keyword arguments.
Every post_*
method has access to path parameters
and additional keyword argument respectively:
post_data(data=data, **path_parameters)
post_head(head=head, **path_parameters)
post_render(html=html, **path_parameters)
# my_plugin.py
from statiq import PluginBase
class MyPlugin(PluginBase):
def pre_data(self, *args, **kwargs):
# alter the route params
kwargs["my_arg"] = "some value"
def post_data(self, *args, **kwargs):
# get the data
data = kwargs.get("data")
# do something with the data
data["some_key"] = "some value"
def pre_head(self, *args, **kwargs):
# alter the route params
kwargs["my_arg"] = "some value"
def post_head(self, *args, **kwargs):
# get the head
head = kwargs.get("head")
# do something with the head
head.append("<meta name='some-meta' content='some value'>")
def pre_render(self, *args, **kwargs):
# alter the route params
kwargs["my_arg"] = "some value"
def post_render(self, *args, **kwargs):
# get the html
html = kwargs.get("html")
# do something with the html
html = html.replace("some text", "some other text")
# config.py
from my_plugin import my_plugin
PLUGINS = [
my_plugin,
]
The plugins will be executed in the order they are defined in the PLUGINS
list.
For example:
# config.py
from my_plugins import my_plugin1, my_plugin2
PLUGINS = [
my_plugin1,
my_plugin2,
]
Given the plugins implement all methods, the order will be as follows:
my_plugin1.pre_data
my_plugin2.pre_data
get_data() from the page.py
my_plugin1.post_data
my_plugin2.post_data
my_plugin1.pre_head
my_plugin2.pre_head
get_head() from the page.py
my_plugin1.post_head
my_plugin2.post_head
my_plugin1.pre_render
my_plugin2.pre_render
render the page
my_plugin1.post_render
my_plugin2.post_render
Statiq can handle parsing and copying of static files
In the config.py
file you need to add two properties STATIC_PATHS
and STATIC_OUTPUT_PATHS
.
STATIC_PATHS = [
{
"path": "src"
}
]
STATIC_OUTPUT_PATH = "output"
Now you just need to run the static copy
command and the files will be copied to the output
folder.
statiq static copy
The STATIC_PATHS
property is used to define the paths to the static files that will be parsed and copied to the STATIC_OUTPUT_PATH
folder.
It should be a list of dictionaries containg path
which points to a folder or a file and a optional regex
property which is used to filter the files that will be parsed.
STATIC_PATHS = [
{
"path": "src",
"regex" r"(.*)\.html$",
}
]
The STATIC_OUTPUT_PATH
property is used to define the path to the folder where the static files will be copied.
STATIC_OUTPUT_PATH = "output"
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
FAQs
Statiq is a static site generator
We found that statiq demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.