A file format-agnostic static site generator
If you already have Rust and Cargo installed:
cargo install mksite
Alternatively, you can install via git:
cargo install --git https://github.com/alterae/mksite
mksite <COMMAND>
Commands:
build Build the site according to `mksite.toml`
clean Delete all build outputs
init Initialize a `mksite.toml` file in the current directory
new Scaffold an empty site in a new directory
help Print this message or the help of the given subcommand(s)
Options:
-q, --quiet Do not print log messages
--log-level <LOG_LEVEL> What level of logging to enable (error, warn, info, debug, or trace) [default: info]
-h, --help Print help information
-V, --version Print version information
mksite
is a program for turning a tree of text files into a different tree of text files, usually a website. A typical mksite
project has the following structure:
mksite.toml
— Themksite.toml
file is the core of a project, and defines the names of the other significant directories, the data available to templates, and the transforms to apply to files.layout/
(optional) — Thelayout/
directory contains layouts, such as html boilerplate, to be applied to files after they are transformed. If you don't want any layouts, or don't want to usemksite
's layout system, this folder can be safely omitted. The name of thelayout/
directory can be customized inmksite.toml
.out/
(generated) — Theout/
directory is generated bymksite
when the site is built, and contains the transformed contents of thesrc/
directory, as well as the contents of thestatic/
directory, copied as-is. The name of theout/
directory can be customized inmksite.toml
.src/
— Thesrc/
directory holds all the non-static source files for the website. Files insrc
must be valid UTF-8 and can contain template expressions using the Tera templating language. Other than that, they can be anything: LaTex, HTML, Markdown, your own custom markup language, or something else entirely. The name of thesrc/
directory can be customized inmksite.toml
.static/
(optional) — Thestatic/
directory contains static files, such as stylesheets or images, which are copied as-is to theout/
directory. No templating or transformation occurs. The name of thestatic/
directory can be customized inmksite.toml
.
An example mksite.toml
file looks like this:
dirs.src = "src"
dirs.out = "out"
dirs.static = "static"
dirs.layout = "layout"
[data]
author = { name = "Jane Doe", email = "[email protected]" }
copyright = 2022
[transforms]
md.html = "pandoc -f markdown -t html"
scd.html = ["scdoc", "pandoc -f man -t html"]
The first four lines tell mksite
the names of the src/
, out/
, static/
, and layout/
directories, respectively. Changing these will change where mksite
reads and writes data. For example, dirs.out = "www"
would cause mksite
to write the build output in a folder called www/
.
Next is the data
section, which is where you can define arbitrary data that will be passed to the template rendering. In templates, this data will be made available under the data
variable. For details on the template syntax, see the Tera documentation.
Finally, we have the transforms
section. Transforms are commands or chains of commands that take a stream of bytes on standard input, and return a stream of bytes for standard output. Transforms can be used to trivially implement many features mksite
does not natively support, such as markdown rendering and syntax highlighting. The basic syntax of a transform definition is in.out = "command"
or in.out = ["command1", "command2", ...]
where in
is the file extension the transform operates on, out
is the file extension the transform produces, and command
is a command to pipe the page through. For more details on the finer points of transforms, see below.
All fields in this config file are optional.
Layouts are simply Tera templates located in the layout/
directory that accept an additional page.content
variable. Layouts must be valid UTF-8, but aside from that they can be any format.
An example layout file looks like this.
<!-- layout/_.html -->
<!DOCTYPE html>
<html>
<head></head>
<body>
<!-- The "| safe" prevents Tera from html-escaping the content. -->
{{ page.content | safe }}
</body>
</html>
There are two kinds of layouts: default layouts and override layouts:
Override layouts have the same name, extension, and relative path as a specific file in the out/
directory, and only apply to that file. For example, the layout layout/blog/index.html
will only apply to the page out/blog/index.html
.
Default layouts have the name _.ext
, where ext
is some file extension. Default layouts apply to all files in the corresponding directory and in nested directories that don't have a default layout. For example:
layout/
_.html
blog/
_.html
index.html
In this example, layout/blog/_.html
will apply to all html files in out/
except index.html
, and layout/_.html
will apply to every html file in out/
except the contents of the blog
directory.
Note Layouts are applied after transforms, based on the file extension of the transform output. As a result, a layout like
_.html
will apply to all generated html files, regardless of whether these html files were hand-written or generated from markdown or something else via a transform.
If no applicable layouts are found for a file, or if there is no layout/
no layout will be applied.
If an applicable layout exists, but you would like to prevent it from being applied to a file or folder, you can define an "empty" layout like so:
{{ page.content | safe }}
A transform has an input extension, an output extension, and a command or chain of commands.
Each page in src/
with a file extension matching a transform's input extension is piped into the transform as a stream of bytes, and the resulting stream of bytes is written to a file in the out/
directory with the same name and path, and a file extension matching the transform's output extension. Each page can be piped to multiple transforms, and multiple transforms can output the same format. The relationship between inputs and outputs is many-to-many.
Warning It is important to note that the inputs and outputs of transforms are streams of arbitrary bytes, not necessarily valid UTF-8 strings. This is important for interfacing with external non-rust tools, but there are some caveats:
Though this may change in the future, at present all templates and layouts must be valid UTF-8. This means that while transforms can both input and output arbitrary bytes, the original input to a transform (a file in the
src/
directory) will be UTF-8. Additionally, layouts for non-UTF-8 files are not supported, and attempting to define a layout for, say, a
If a transform has a single command, pages are piped to that command, and the output of the command is written to the output file. For example, these transforms:
[transforms]
md.html = "pandoc -f markdown"
md.pdf = "pandoc -f markdown -t pdf"
Will use pandoc to produce an html file and a pdf document in out/
for every markdown file in src/
.
If a transform has a chain of commands, pages are piped to each command in the chain in order, and the ouput of the last command is written to the output file, like with shell pipelines. For example:
[transforms]
scd.html = ["scdoc", "pandoc -f man"]
Will use scdoc
to generate a man page from each .scd
file, and immediately pipe that man page to pandoc
to convert it to html.
Pull requests and issues are welcome, but please ensure you run cargo fmt
before submitting a PR.
See the docs/
folder for an example of a website built using mksite
.
mksite
is licensed under the MIT License.