11 个版本 (破坏性更新)
0.8.1 | 2024年2月23日 |
---|---|
0.8.0 | 2023年10月28日 |
0.7.1 | 2023年7月23日 |
0.6.0 | 2022年11月20日 |
0.0.0 | 2022年3月26日 |
#8 in 模板引擎
4,122 每月下载量
用于 24 个包(12 直接使用)
310KB
7.5K SLoC
upon
一个简单、强大的模板引擎,具有最少的依赖项和可配置的分隔符。
目录
概述
语法
- 表达式:
{{ user.name }}
- 条件语句:
{% if user.enabled %} ... }
- 循环:
{% for user in users %} ... }
- 嵌套模板:
{% include "nested" %}
- 可配置的分隔符:
<? user.name ?>
,(( if user.enabled ))
- 任意用户定义的过滤器:
{{ user.name | replace: "\t", " " }}
引擎
- 清晰且文档齐全的API
- 可定制的值格式化器:
{{ user.name | escape_html }}
- 渲染到
String
或任何std::io::Write
实现 - 使用任何
serde
可序列化值进行渲染 - 方便的宏,用于快速渲染:
upon::value!{ name: "John", age: 42 }
- 使用
{:#}
显示时提供清晰的错误信息 - 格式无关(默认不转义HTML中的值)
- 最小依赖和良好的运行时性能
为什么还需要另一个模板引擎?
确实,Rust已经有大量的模板引擎了!
我创建了upon
,因为我需要一个具有运行时编译模板、可配置语法分隔符和最小依赖的模板引擎。我也不需要支持模板语法中的任意表达式,但偶尔我需要比输出简单值更灵活的东西(因此有过滤器)。性能也是我的一个关注点,像Handlebars和Tera这样的模板引擎功能丰富,但渲染速度可能比TinyTemplate慢五到七倍。
基本上,我想要一个类似TinyTemplate的模板引擎,支持可配置的分隔符和用户定义的过滤器函数。语法灵感来源于像Liquid和Jinja这样的模板引擎。
MSRV
目前,upon
支持的最小Rust版本是1.65。禁用filters
功能,可以降低到Rust 1.60。MSRV将在破坏性版本中仅增加。
入门指南
首先,将crate添加到您的Cargo清单中。
cargo add upon
现在构建一个 Engine
。该引擎存储语法配置、过滤器函数、格式化器和编译后的模板。通常,您只需要在程序的生命周期内构建一个引擎。
let engine = upon::Engine::new();
接下来,使用 add_template(..)
编译和存储模板到引擎中。
engine.add_template("hello", "Hello {{ user.name }}!")?;
最后,通过调用 template(..)
、render(..)
并将其渲染为字符串来渲染模板。
let result = engine
.template("hello")
.render(upon::value!{ user: { name: "John Smith" }})
.to_string()?;
assert_eq!(result, "Hello John Smith!");
进一步阅读
syntax
模块文档概述了模板语法。filters
模块文档描述了过滤器及其工作原理。fmt
模块文档包含有关值格式化程序的信息。- 除了当前文档中的示例外,仓库中的
examples/
目录还包含一些更具体的代码示例。
功能
以下是一些可用的 crate 功能。
-
filters
(默认启用) — 启用模板中对过滤器的支持(参见Engine::add_filter
)。这不会影响值格式化程序(参见Engine::add_formatter
)。禁用此功能将提高编译时间。 -
serde
(默认启用) — 启用所有 serde 支持,并拉取serde
crate 作为依赖项。如果禁用,则可以使用render_from(..)
来渲染模板,并使用Value
的From
实现 -
unicode
(默认启用) — 启用 unicode 支持,并拉取unicode-ident
和unicode-width
crate。如果禁用,则模板中不再允许使用 unicode 标识符,错误格式化将使用.chars().count()
要禁用所有功能或使用子集,您需要在您的 Cargo 清单中设置 default-features = false
,然后启用您希望启用的功能。例如,要使用 serde
但禁用 filters
和 unicode
,您将执行以下操作。
[dependencies]
upon = { version = "...", default-features = false, features = ["serde"] }
示例
嵌套模板
您可以使用名称通过 {% include .. %}
包含其他模板。
let mut engine = upon::Engine::new();
engine.add_template("hello", "Hello {{ user.name }}!")?;
engine.add_template("goodbye", "Goodbye {{ user.name }}!")?;
engine.add_template("nested", "{% include \"hello\" %}\n{% include \"goodbye\" %}")?;
let result = engine.template("nested")
.render(upon::value!{ user: { name: "John Smith" }})
.to_string()?;
assert_eq!(result, "Hello John Smith!\nGoodbye John Smith!");
渲染到写入器
将模板渲染为字符串而不是直接渲染,可以使用 std::io::Write
实现者,通过 to_writer(..)
方法。
use std::io;
let mut engine = upon::Engine::new();
engine.add_template("hello", "Hello {{ user.name }}!")?;
let mut stdout = io::BufWriter::new(io::stdout());
engine
.template("hello")
.render(upon::value!{ user: { name: "John Smith" }})
.to_writer(&mut stdout)?;
// Prints: Hello John Smith!
短期生命周期的借用模板
如果模板源的生命周期短于引擎的生命周期,或者您不需要存储编译后的模板,您还可以使用 compile(..)
函数直接返回模板。
let template = engine.compile("Hello {{ user.name }}!")?;
let result = template
.render(&engine, upon::value!{ user: { name: "John Smith" }})
.to_string()?;
assert_eq!(result, "Hello John Smith!");
自定义模板存储和函数
compile(..)
函数还可以与自定义模板存储结合使用,这可以允许更高级的使用场景。例如:相对模板路径或控制模板访问。
let mut store = std::collections::HashMap::<&str, upon::Template>::new();
store.insert("hello", engine.compile("Hello {{ user.name }}!")?);
store.insert("goodbye", engine.compile("Goodbye {{ user.name }}!")?);
store.insert("nested", engine.compile("{% include \"hello\" %}\n{% include \"goodbye\" %}")?);
let result = store.get("nested")
.unwrap()
.render(&engine, upon::value!{ user: { name: "John Smith" }})
.with_template_fn(|name| {
store
.get(name)
.ok_or_else(|| String::from("template not found"))
})
.to_string()?;
assert_eq!(result, "Hello John Smith!\nGoodbye John Smith!");
基准测试
在 Rust 生态系统中的几个流行的模板渲染引擎中进行了 upon 的基准测试。显然,每个引擎都具有完全不同的功能集,因此基准测试仅比较它们共享的一些功能的性能。
- handlebars v4.3.7
- liquid v0.26.4
- minijinja v1.0.5
- tera v1.19.0
- tinytemplate v1.2.1
- upon v0.7.0
基准测试是在一个安静的云机器上使用 criterion 进行的。
主机
- Vultr.com
- 4 CPU
- 8192 MB RAM
- Ubuntu 22.04
- Rust 1.71.0
许可证
许可证:Apache License,版本 2.0(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- 或 MIT 许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
- 根据您的选择。
依赖关系
~110–445KB
~110–445KB