code: better Readme, implementing custom intializer

This commit is contained in:
Gabor Körber 2025-01-13 21:40:44 +01:00
parent 726a21b257
commit f821e2d7d7
5 changed files with 127 additions and 12 deletions

15
Cargo.lock generated
View File

@ -1589,6 +1589,8 @@ dependencies = [
"minijinja", "minijinja",
"minijinja-autoreload", "minijinja-autoreload",
"serde", "serde",
"serde_json",
"tracing-subscriber",
] ]
[[package]] [[package]]
@ -3024,6 +3026,16 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-serde"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
dependencies = [
"serde",
"tracing-core",
]
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.19" version = "0.3.19"
@ -3034,12 +3046,15 @@ dependencies = [
"nu-ansi-term", "nu-ansi-term",
"once_cell", "once_cell",
"regex", "regex",
"serde",
"serde_json",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing", "tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
"tracing-serde",
] ]
[[package]] [[package]]

View File

@ -4,17 +4,35 @@
name = "loco-minijinja-engine" name = "loco-minijinja-engine"
version = "0.14.0" version = "0.14.0"
edition = "2021" edition = "2021"
# For releasing:
authors = ["Gabor Körber <gab@g4b.org>"]
description = "Initializers to use Minijinja Templating Engine in Loco.rs"
repository = "https://github.com/g4borg/loco_minijinja_engine"
homepage = "https://github.com/g4borg/loco_minijinja_engine"
# documentation = "https://docs.rs/my_library"
keywords = ["loco", "loco.rs", "minijinja"]
categories = ["convenience", "bindings"]
# license = "MIT OR Apache-2.0"
readme = "README.md"
[features] [features]
# default = ["autoreloader"]
autoreloader = ["dep:minijinja-autoreload"] autoreloader = ["dep:minijinja-autoreload"]
[workspace.dependencies] [workspace.dependencies]
loco-rs = { version = "0.14.0", default-features = false } loco-rs = { version = "0.14.0", default-features = false }
[dependencies] [dependencies]
async-trait = "0.1" async-trait = "0.1"
axum = "0.8" axum = "0.8"
loco-rs = { workspace = true } loco-rs = { workspace = true }
tracing-subscriber = { version = "0.3", features = [
"env-filter",
"json",
] } # required by loco-rs to build correctly
minijinja = { version = "2.6", features = ["loader"] } minijinja = { version = "2.6", features = ["loader"] }
minijinja-autoreload = { version = "2.6", optional = true } minijinja-autoreload = { version = "2.6", optional = true }
serde = "1.0" serde = "1.0"
serde_json = { version = "1" }

View File

@ -1,3 +1,49 @@
# Minijinja Engine for Loco.rs # Minijinja Engine for Loco.rs
This crate allows you to integrate [Minijinja](https://github.com/mitsuhiko/minijinja) as Template renderer into [Loco.rs](https://github.com/loco-rs/loco) This crate allows you to integrate [Minijinja](https://github.com/mitsuhiko/minijinja) as Template renderer into [Loco.rs](https://github.com/loco-rs/loco)
## Usage
### Use autoreloader
The `autoreloader` feature automatically uses the `minijinja-autoreloader` instead of a single environment.
Just set in your Cargo.toml:
```toml
loco-minijinja-engine = { features = ["autoreloader"] }
```
### Default Settings
If you want the standard initializer, so access `"assets/templates"` as your template directory, and a standard minijinja renderer as it comes out of the box, just use in your `app.rs`:
```rust
...
async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> {
Ok(vec![Box::new(loco_minijinja_engine::MinijinjaViewEngineInitializer)])
}
...
```
### Custom Environment or Template Directory
If you want a different directory for your templates, e.g. stay with `"assets/views"` like the Tera setup in loco, use the custom initializer in your `app.rs`:
```rust
...
async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> {
let environment = Environment::new();
Ok(vec![Box::new(
loco_minijinja_engine::MinijinjaViewEngineConfigurableInitializer::new(
"assets/views".to_string(),
Some(environment),
),
)])
}
```
(Note, that because of the trait layout, I cannot prevent two clones and 'static for the custom Environment, so if you need anything more dynamic, feel free to copypaste the initializer, and initialize the Environment in the closure)

View File

@ -40,7 +40,10 @@ impl Hooks for App {
async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> { async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> {
Ok(vec![Box::new( Ok(vec![Box::new(
loco_minijinja_engine::MinijinjaViewEngineInitializer, loco_minijinja_engine::MinijinjaViewEngineConfigurableInitializer::new(
"assets/templates".to_string(),
None,
),
)]) )])
} }

View File

@ -6,7 +6,7 @@ use loco_rs::{
errors::Error, errors::Error,
Result, Result,
}; };
use minijinja::{filters::default, path_loader, Environment}; use minijinja::{path_loader, Environment};
#[cfg(feature = "autoreloader")] #[cfg(feature = "autoreloader")]
use minijinja_autoreload::AutoReloader; use minijinja_autoreload::AutoReloader;
use serde::Serialize; use serde::Serialize;
@ -28,10 +28,13 @@ pub struct MinijinjaView<'a> {
impl MinijinjaView<'_> { impl MinijinjaView<'_> {
pub fn build() -> Result<Self> { pub fn build() -> Result<Self> {
Self::from_custom_dir(&TEMPLATES_DIR) Self::from_custom(&TEMPLATES_DIR, None)
} }
pub fn from_custom_dir<P: AsRef<Path>>(path: &P) -> Result<Self> { pub fn from_custom<P: AsRef<Path>>(
path: &P,
custom_environment: Option<Environment<'static>>,
) -> Result<Self> {
if !path.as_ref().exists() { if !path.as_ref().exists() {
return Err(Error::string(&format!( return Err(Error::string(&format!(
"missing templates directory: `{}`", "missing templates directory: `{}`",
@ -43,20 +46,19 @@ impl MinijinjaView<'_> {
#[cfg(feature = "autoreloader")] #[cfg(feature = "autoreloader")]
let reloader = AutoReloader::new(move |notifier| { let reloader = AutoReloader::new(move |notifier| {
let mut environment = Environment::new(); let cust_env = custom_environment.clone();
let mut env = cust_env.unwrap_or_else(Environment::new);
let template_path = template_path.clone(); let template_path = template_path.clone();
env.set_loader(path_loader(&template_path));
environment.set_loader(path_loader(&template_path));
notifier.watch_path(template_path, true); notifier.watch_path(template_path, true);
Ok(environment) Ok(env)
}); });
#[cfg(not(feature = "autoreloader"))] #[cfg(not(feature = "autoreloader"))]
let environment = { let environment = {
let mut environment = Environment::new(); let mut env = custom_environment.unwrap_or_else(Environment::new);
environment.set_loader(path_loader(&template_path)); env.set_loader(path_loader(&template_path));
environment env
}; };
Ok(Self { Ok(Self {
@ -126,3 +128,34 @@ impl Initializer for MinijinjaViewEngineInitializer {
Ok(router.layer(Extension(ViewEngine::from(jinja)))) Ok(router.layer(Extension(ViewEngine::from(jinja))))
} }
} }
pub struct MinijinjaViewEngineConfigurableInitializer {
template_directory: String,
custom_environment: Option<Environment<'static>>,
}
#[async_trait]
impl Initializer for MinijinjaViewEngineConfigurableInitializer {
fn name(&self) -> String {
"minijinja".to_string()
}
async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result<AxumRouter> {
let custom_environment = self.custom_environment.clone(); // as this is a &self function, we have to clone here.
let jinja =
MinijinjaView::from_custom::<String>(&self.template_directory, custom_environment)?;
Ok(router.layer(Extension(ViewEngine::from(jinja))))
}
}
impl MinijinjaViewEngineConfigurableInitializer {
pub fn new(
template_directory: String,
custom_environment: Option<Environment<'static>>,
) -> Self {
MinijinjaViewEngineConfigurableInitializer {
template_directory: template_directory,
custom_environment: custom_environment,
}
}
}