ukko is a powerful static site generator written in Clojure.
ukko is published under AGPL-3.0 License.
You have two options to install ukko
.
This is reasonable if you want to develop on ukko
itself.
Prerequisites:
- Clojure
- Leiningen
- rsync
- pandoc (soon to be optional)
- linkchecker (optional)
- sassc (optional)
- geckodriver (optional), or chromedriver or safari
- Clone this repository.
- Run
lein bin
.
Premise: You have Docker installed.
Copy/paste this into your shell and you will have a ~/bin/ukko
file.
cat >> ~/bin/ukko <<EOF
#!/bin/sh
docker run -it --rm -v \`pwd\`:/project twohundredok/ukko /bin/bash -c "/bin/ukko \$@"
EOF
chmod +x ~/bin/ukko
Much like any other static site generator ukko collects information from input files and generates and writes output files.
🧐 For brevity the documentation follows some general typographic rules:
- Keys (aka. properties) will be written in italics
- Values will be written in code blocks (monospaced font)
- Explanations will generally use the default values (in code blocks) with the corresponding key in parenthesis and italics
Here is an example:
Output files are written to public
(target-path).
😎 This means the path files are written to, here
public
, can be changed by setting the option target-path inukko.yml
.
ukko collects information from 5 locations:
ukko.yml
assets
(assets-path)site
(site-path)layouts
(layouts-path)data
(data-path)
If present ukko reads the file ukko.yml
, which can be used to
overwrite any global settings and defaults.
- assets-path, default:
assets
- site-path, default:
site
- layouts-path, default:
layouts
- data-path, default:
data
- target-path, default:
public
- ignore-file-patterns, default:
["^\\."]
- Changes to a file matching one of these patterns will not trigger a rebuild.
- The default pattern ignores temporary files written by Emacs.
- linkcheck-params, default:
nil
- Additional parameters that will be applied to
linkcheck
when runningukko -l
.
- Additional parameters that will be applied to
- target-extension, default:
.html
- format, default:
passthrough
- layout, default:
[post, blog]
- priority, default:
50
As the data provided by ukko.yml
is easily accessible from any
template it may very well be used to provide any additional metadata
like:
- site-url
- site-title
- …
All files in assets
(assets-path) are treated as ready-to-publish
and will be synced (via rsync) to public
(target-path) without any
further processing.
Files in site
(site-path), in ukko called “artifacts”, are expected
to need processing before being published. Furthermore any file in
site
(site-path) is expected to provide a YAML front matter.
🤓 The concept of a YAML front matter was popularized by the static site generator jekyll, although webby by Tim Pease had it as early as 2008. Credit where credit is due!
The YAML front matter is used to provide instructions on how to
process the artifact for publishing, as well as any additional
metadata. The front matter is closed with a YAML document separator
---
(a line with only three dashes). The remainder of the file, after the
front matter, is called template.
🧐 It is not necessarily a template, it can also be just content. In ukko it is still called template.
The naming and location of the files in site
(site-path) generally
will be used to determine the naming and location in public
(target-path). But as you’ll see later there are exceptions to that
rule. Solely the file extension is irrelevant, as it will be replaced
with .html
(target-extension).
As the default format is passthrough
(format) any file that does
not specify format in its front matter explicitly will just have its
template copied into its target location (target-path). It still
needs to have a front matter, though. Files in site
that do not have
a valid front matter (invalid or none) will be ignored during
processing.
🤓 It is allowed to place files without front matter in
site
(site-path). For example files containing org fragments to be included in other org files. In that case it is considered a feature that these files due to the absence of a front matter will be ignored.
Within ukko an artifact is represented as a Clojure map of its front matter with the following additional keys
- path (the path to the source file)
- template (the content of the source file without the front matter)
- mtime (the date of last modification of the file as iso date string)
Here are some properties that control how artifacts are processed:
Formats transform the template. Available formats are:
passthrough
md
(Markdown, via flexmark)org
(org-mode, via Emacs)fleet
(templating, via fleet)scss
(via sassc)- All 40+ formats supported by Pandoc
Formats can be chained. By providing a list of formats the template can be passed through mulitple formats. This could for example be used to generate Markdown from a Fleet template, which is then converted to HTML.
🤓 Transforms are implemented with Clojure’s multimethods and thus are easily extendable. Pull requests are very welcome!
Layout specifies templates from layouts
(layouts-path) that will
be used the wrap the resulting html fragment. More about that in the
section about layouts.
When using a templating format, like fleet
, the template receives
a context “ctx” in which it is evaluated. Without setting scope the
context is the global context with the current artifact merged.
🤓 This means that any property set in
ukko.yml
will act as a default and any default can be overwritten by the artifact’s front matter.
Sometimes an artifact’s template depends on other artifacts. In this
case the order of processing is crucial. Artifacts are processed in
order of priority, and in case of equal priority alphabetically. By
overwriting the default priority of 50
with a higher value it can be
ensured that the given artifact is processed later.
Collection is a powerful property that allows to render one template into multiple output files. Collection is used to provide a list (or vector, or map) of which each item results in its own output file. There are several ways in which the value of collection will be interpreted, based on the type of value provided:
- a vector (aka. YAML list)
- a string (any YAML string)
- a map (aka. YAML object)
A vector needs to be a list of Clojure keywords and will be used to navigate the context as with Clojure’s get-in. It is mainly used to drill down into the context, so this doesn’t need to happen in the template itself. The items of the structure retrieved with the navigator will be the new context passed to the template.
A string is the most versatile way to define a collection, as the string will be evaluated as Clojure code. The return value will be the new context passed to the template.
A map will yield a cross-product of the values of the map interpreted as navigators. The items if the collections will be available in the cross-product items under the keys of the map. The cross-product items will be the new context passed to the template. This means that during processing any artifact that defines a collection will in fact be replaced by multiple artifacts, one for each item in the collection. The target-path of the new artifact is relative to original artifact (it shares its path), but will be derived from the id of the item.
😎 This will be your new SEO-Power-Tool.
Layouts are handled much like artifacts in site
(site-path), but
– as they are used to wrap html fragments generated by artifacts –
need to provide an actual template using a templating format, like
fleet
. (As opposed to artifacts, layouts can currently only be
transformed by one format.)
Layouts can be chained, much like formats. This means artifacts can specify a list of layouts where the former will be wrapped by the later. In other words layouts will be applied in the order they are listed.
🤓 In fact by default layout is defined as
[post, blog]
, assuming that the majority of files in a typical setup will be blog posts, so that when writing a blog post you can omit layout and go with the default.
ukko uses fsdb to collect information from data
(data-path) and
thus supports the most common formats for structured data. It provides
what it finds as structured data via data in the root context to any
template.
😎 This in combination with scope or collection makes it really powerful. Just imagine the possibilities.
ukko without any argument will generate the site, write it to public
(target-path) and quit. Additional features can be turned on by
passing arguments:
-c, --continuous Regenerate site on file change -l, --linkcheck After generating the site check links -p, --port PORT Port for http server, default: 8080 -f, --filter FILTER Generate only files matching the regex FILTER -q, --quiet Suppress output (not yet implemented) -s, --server Run a http server -b, --browser BROWSER Start a browser with live-reload (either firefox, chrome, or safari) -v, --verbose Verbose output (not yet implemented)
By default, your browser will start with an empty profile. Optionally, if you want to start your browser with a specific profile (for example for HiDPI settings or to include addons), you can set the profile in an environment variable:
FIREFOX_PROFILE=~/.mozilla/firefox/xmcjb934.geckodriver ukko -c -s -b firefox
- Run Firefox with
-P
,-p
or-ProfileManager
key as the official page describes. - Create a new profile and run the browser.
- Setup the profile as you need.
- Open
about:support
page. Near theProfile Folder
caption, press theShow in Finder
button. A new folder window should appear. Copy its path from there.
- In the right top corner of the main window, click on a user button.
- In the dropdown, select “Manage People”.
- Click “Add person”, submit a name and press “Save”.
- The new browser window should appear. Now, setup the new profile as you want.
- Open
chrome://version/
page. Copy the file path that is beneath theProfile Path
caption.
Our very own https://200ok.ch is, of course, generated via ukko.
😭 An example project would be nice, but sadly there is none atm.
Here is an initial directory structure to run ukko against.
. ├── assets ├── data ├── layouts ├── public (will be created by ukko) ├── site └── ukko.yml (optional)