Lately, I started building apps with Tauri. Contrary to common opinion, I prefer to build the frontends of my hobby projects without frameworks and use vanilla HTML and JavaScript instead. This works quite well, but as soon as you start having multiple pages, you want at least some templating to reduce duplication of common components.
When using the rocket web framework I already got used to tera templates for that purpose. I wanted the same when using Tauri. How hard can it be? It turns out: quite easy.
First, we need to add tera to our build dependencies on the cargo.toml
[build-dependencies]
tauri-build = { version = "2.0.2", features = [] }
tera = "*"
One consideration is the question of when the templates should be rendered. At compile time, or during runtime. As I do not have any meaningful context at the moment, I opted for rendering during compilation. For this, I extended the build.rs
file already generated by Tauri.
use std::{collections::HashMap, fs};
use tera::Tera;
fn main() {
// Execute this every time the project is built, to render templates
println!("cargo:rerun-if-changed=NULL");
// Create a new Tera instance and add a template folder
let tera = Tera::new("../templates/**/*")
.expect("Unable to initialize tera templating instance");
// Prepare the context with some data
// Left empty here, because we only render the
// templates and do not use any context variables
let context = tera::Context::new();
let mappings = HashMap::from([
("about.tera", "about.html"),
("index.tera", "index.html"),
]);
// Render the template with the given context
for (source, destination) in mappings {
let rendered = tera.render(source, &context)
.expect("Rendering process failed");
fs::write(format!("../src/{}", destination), rendered)
.expect("Failed to write output");
}
tauri_build::build()
}
I chose to list the source template files and the output files explicitly, but this could also be done by using a glob pattern. Now the templates will be regenerated every time the project is built.