Skip to main content

alun_template/
lib.rs

1//! Template engine abstraction — 运行时模板用 minijinja
2
3use std::sync::Arc;
4use alun_core::Result;
5
6/// 模板引擎(封装 minijinja,启动时一次性加载模板目录)
7#[derive(Clone)]
8pub struct TemplateEngine {
9    /// minijinja 环境(持有模板编译后的模板)
10    env: Arc<minijinja::Environment<'static>>,
11}
12
13impl TemplateEngine {
14    /// 创建空引擎(不加载任何模板,仅支持 `render_str`)
15    pub fn new() -> Self {
16        Self { env: Arc::new(minijinja::Environment::new()) }
17    }
18
19    /// 加载模板目录,模板通过文件名引用(如 "index.html", "dashboard.html")
20    pub fn from_dir(dir: &str) -> Result<Self> {
21        let mut env = minijinja::Environment::new();
22        env.set_loader(minijinja::path_loader(dir));
23        Ok(Self { env: Arc::new(env) })
24    }
25
26    /// 渲染指定模板
27    ///
28    /// # 参数
29    /// - `name`: 模板文件名(如 "index.html"),需先用 `from_dir` 加载目录
30    /// - `ctx`: 模板上下文(任何实现 Serialize 的类型)
31    pub fn render<C: serde::Serialize>(&self, name: &str, ctx: &C) -> Result<String> {
32        let tmpl = self.env
33            .get_template(name)
34            .map_err(|e| alun_core::Error::Template(format!("模板加载失败 {}: {}", name, e)))?;
35        let ctx_val = minijinja::value::Value::from_serialize(ctx);
36        tmpl.render(&ctx_val)
37            .map_err(|e| alun_core::Error::Template(format!("模板渲染失败: {}", e)))
38    }
39
40    /// 从字符串渲染(用于动态模板内容)
41    pub fn render_str<C: serde::Serialize>(&self, source: &str, ctx: &C) -> Result<String> {
42        let tmpl = self.env
43            .template_from_str(source)
44            .map_err(|e| alun_core::Error::Template(format!("模板编译失败: {}", e)))?;
45        let ctx_val = minijinja::value::Value::from_serialize(ctx);
46        tmpl.render(&ctx_val)
47            .map_err(|e| alun_core::Error::Template(format!("模板渲染失败: {}", e)))
48    }
49}
50
51impl Default for TemplateEngine {
52    fn default() -> Self { Self::new() }
53}