A blazingly-fast static site generator.
{{ end("body") }} ``` ### HTML and Markdown Pages HTML pages are regular HTML files, which can contain template tags. They define sections which are rendered into the root template. Markdown pages are markdown files, starting with frontmatter containing metadata about the file, and then the content of the page. These are converted into HTML, rendered into the nearest `md.html` template through the `$self` variable, and the section from this are then rendered into the root template. Again, this is clearer with an example. `my_page.md`: ```markdown --- title: "My Page" author: "William Henderson" --- # My Page Markdown content... ``` `md.html`: ```html {{ begin("head") }}By {{ $self.author }}
{{ $self.content }} {{ end("body") }} ``` `root.html` as above. ### JSON Data JSON data files can also be sources of data for a Stuart website using the `import` templating function in an HTML page, which imports a JSON file as a variable. ### Static Files Static files should be placed in the `static` directory, which is merged with the built content at the end of the build. Filename conflicts will cause the build to fail. ### Build Scripts Build scripts should be placed in the `scripts` directory. Currently, the only scripts that Stuart supports are `onPreBuild` and `onPostBuild`. On Windows, these should have `.bat` extensions, and on Linux, they should have either `.sh` extensions or no extension at all. These scripts are run before and after the build, respectively. The `onPostBuild` script can access metadata about the build in the `metadata.json` file, if `save_metadata` is enabled in the project configuration. If a pre-build script wants to create files in the output directory, it should do so in the `temp` directory, which Stuart will merge into the output directory at the end of the build. This is to avoid conflicts with the build system, as writing directly to the output directory could cause unexpected behaviour. Certain environment variables are set for build scripts to provide information about the build. These are: | Name | Description | | --- | --- | | `STUART_MANIFEST_PATH` | The full path to the `stuart.toml` manifest file. | | `STUART_MANIFEST_DIR` | The full path to the directory containing the `stuart.toml` manifest file. | | `STUART_TEMP_DIR` | The full path to the `temp` directory where files should be placed during pre-build script execution. | | `STUART_OUT_DIR` | The full path to the output directory. | | `STUART_ENV` | The environment that Stuart is running in. This will be either `production`, `development`, or `benchmark`. | ## Templating Language The Stuart templating language consists of two main parts: variables and functions. Variables are used to insert data into the template, and functions allow for more complex behaviour such as iteration and selection. All template tags are enclosed in double curly braces. Variables are prefixed with a dollar sign. ### Variables A basic variable can be inserted into the template as follows: ```html {{ $variable }} ``` All variables are JSON values, so object values can be accessed using dot notation: ```html {{ $variable.property }} ``` Environment variables are accessible within templates using the `$env` variable, so for example, to get the value of the `STUART_ENV` environment variable, you would use `{{ $env.STUART_ENV }}`. ### Functions Functions are called using the following syntax: ```html {{ function_name(arg1, arg2, positional_arg="value", ...) }} ``` Stuart currently supports the following functions: | Name | Description | Example(s) | | --- | --- | --- | | `begin` | Begins a section. | `begin("section_name")` | | `end` | Ends a section or another function. | `end("section_name")`, `end(function_name)` | | `insert` | Inserts a section into the template, only used in `root.html`. | `insert("section_name")` | | `import` | Imports a JSON file as a variable. | `import($data, "data.json")` | | `for` | Iterates over a JSON array or a directory of markdown files. The loop is ended with `end(for)`. | `for($tag, "tags.json")`, `for($post, "posts/", skip=3, limit=3, order="desc", sortby="date")`, `for($item, $array)` | | `dateformat` | Formats a date using the [chrono](https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html) format string. The date input can be any kind of formatted date or timestamp. | `dateformat($date, "%Y-%m-%d")` | | `if[eq,ne,gt,ge,lt,le]` | Performs a comparison between two values. The block is ended with `end(if[eq,ne,...])`. | `ifeq($a, $b)`, `ifge($age, 18)` | | `ifdefined` | Checks if a variable is defined. The block is ended with `end(ifdefined)`. | `ifdefined($variable)`, `ifdefined($variable.property)` | | `else` | Starts the else block for a conditional. | `else()` | | `excerpt` | Creates an excerpt from a string. | `excerpt($post.content, 100)` | | `timetoread` | Calculates the time to read a string in minutes. | `timetoread($post.content)` | ## Plugins Stuart supports dynamically-loaded plugins, which are Rust libraries that provide additional functionality to Stuart. Plugins dependencies are specified in the `stuart.toml` file as described earlier. Plugin functions can be called from within templates by prefixing the function name with the plugin name, for example: ```html {{ my_plugin::my_function() }} ``` If the function name doesn't clash with another function, the plugin name can be omitted. If it does, built-in functions take priority over plugin functions, but the order of plugin functions is undefined. So don't do that. ### Native Plugin API Native plugins are defined using the `define_plugin!` macro in the core crate. They can add functions to Stuart, which are implemented in exactly the same way as the built-in functions, and can also add parsers for new file types. Please refer to the [built-in functions](https://github.com/w-henderson/Stuart/tree/master/stuart-core/src/functions/parsers) for function implementation examples, and to the [image optimization plugin source code](https://github.com/w-henderson/Stuart/tree/master/plugins/imgopt) to see how parsers for new file types can be used. An example of calling the macro is as follows: ```rs declare_plugin! { name: "my_plugin", version: "1.0.0", functions: [ SomeFunctionParser, AnotherFunctionParser ], parsers: [ MyParser ] } ``` You must configure the Cargo project to be compiled as a `cdylib` library, as follows (in `Cargo.toml`): ```toml [lib] crate-type = ["cdylib"] ``` The project must also have `stuart_core` as a dependency in order to use the `define_plugin!` macro and Stuart plugin types. You can disable default features to avoid compiling unnecessary dependencies, as follows: ```toml [dependencies] stuart_core = { version = "*", default-features = false } ``` ### JavaScript Plugin API When compiled with the `js` feature, Stuart can also load plugins written in JavaScript using V8. These can only add functions to Stuart. A plugin is simply a JavaScript module which exports a default object containing the plugin metadata, analogous to the `declare_plugin!` macro in Rust: ```js export default { name: "my_plugin", version: "1.0.0", functions: [ { name: "add", fn: (a, b) => a + b } ] } ``` Stuart variables will automatically be converted to JavaScript objects when passed as arguments, but changes to them will not propagate back to the Rust end automatically. For that, you can use the `STUART` global object to access the plugin API. ```js const self = STUART.get("self"); STUART.set("my_var", `Title: ${self.title}`); ``` For an example of a more complex JavaScript plugin, see [stuart-math](https://github.com/w-henderson/stuart-math), which uses MathJax to render LaTeX.