2个版本

0.0.2 2019年3月5日
0.0.1 2019年2月24日

模板引擎中排名#214

MIT/ApacheLGPL-3.0-or-later

31KB
670

[WIP] wearte 文档 最新版本 构建状态 下载量

wearte代表《W》even《A》nother《R》ust《T》emplate《E》ngine,它是最快的Rust模板引擎之一。它使用类似于Handlebars的语法。

这个crate是从yarte分叉的,修复了snarky许可问题。yarte本身是askama的直接后裔。您可以在LICENSE-MIT中找到他们的许可副本。

为什么需要一个派生模板引擎?

有许多基于mustache或/和handlebars的模板引擎,我从未听说过任何一个将模板编译的任务从编译器中提取出来(例如askama)。通过从这个过程中提取这个任务,我们可以使用我们自己的工具或第三方工具(如LLVM)优化生成的指令。在其他情况下这是不可能的,这将在我们的Web服务器中形成瓶颈,达到毫秒级。正因为如此,wearte将模板放在优先位置,通过静态分配其需求。因此,我们写得比宏write!更快,易于并行化,并在其默认的html转义中使用simd。

总之,派生用于最快和最简单。

入门

将wearte依赖项添加到您的Cargo.toml文件中

[dependencies]
wearte = "0.0.1"

为了在模板中使用结构体,您必须调用过程宏Template。例如,在下面的代码中,我们将使用结构体CardTemplate,然后定义s为具有内容的CardTemplate

use wearte::Template;

#[derive(Template)]
#[template(path = "hello.html")]
struct CardTemplate<'a> {
    title: &'a str,
    body: &'a str,
}

let template = CardTemplate {
    title: "My Title",
    body: "My Body",
};

现在我们的结构体定义好了,让我们在模板中使用它。wearte模板看起来像普通文本,包含嵌入的wearte表达式。

假设文件hello.html看起来像这样

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{body}}
  </div>
</div>

调用模板并将结果分配到String中,然后用wearte::Result包装它返回

template.call()
<div class="entry">
  <h1> My Title </h1>
  <div class="body">
    My Body
  </div>
</div>

模板化

wearte使用开始字符{{和结束字符}}来根据使用的功能解析内部内容。大多数功能由Handlebars定义,例如路径、注释、HTML、助手和部分。其他如将Rust代码添加到模板中,显然由wearte定义。

// precompile your template
#[derive(Template)]
#[template(source = "Hello, {{ name }}!", ext = "txt")]
struct HelloTemplate<'a> {
    name: &'a str,
}

assert_eq!(
    "Hello, world!", 
    HelloTemplate { name: "world" }.call().unwrap() // then call it.
); 

注释

{{!   Comments can be written  }}
{{!--  in two different ways --}}

HTML

wearte会将由{{表达式}}返回的值进行HTML转义。如果您不想让wearte转义值,请使用“三重反引号”,{{{。例如,以下结构体

let t = CardTemplate {
  title: "All about <p> Tags",
  body: "<p>This is a post about &lt;p&gt; tags</p>"
};

和以下模板

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{{body}}}
  </div>
</div>

将得到以下结果

<div class="entry">
  <h1>All About &lt;p&gt; Tags</h1>
  <div class="body">
    <p>This is a post about &lt;p&gt; tags</p>
  </div>
</div>

助手

内置

如果、否则和否则如果助手
{{#if isLiked}}
  Liked!
{{else if isSeen}}
  Seen!
{{else}}
  Sorry ...
{{\if}}
使用助手
let author = Author {
    name: "J. R. R. Tolkien"
};
{{#with author}}
  <p>{{name}}</p>
{{/with}}
每个助手
{{#each into_iter}} 
    {{#- if first || last -}}
        {{ index }} 
    {{- else -}}
        {{ index0 }} 
    {{/-if }} {{ key }} 
{{\-each}}
除非助手
{{#unless isAdministrator-}} 
  Ask administrator.
{{\-unless}}
[WIP] 日志助手
{{#log }} {{log\}}
[WIP] 查找助手
{{#lookup }} {{\lookup}}

[WIP] 用户定义

为了创建用户定义的助手 ..

文字

布尔值、整数、浮点数等不会被转义以提高性能。如果可能,建议使用这些类型。

部分

可以使用部分通过预定义函数生成更快的代码。

{{> path/to/file }}

Rust代码

wearte为您提供在HTML文件中使用原始Rust代码的可能性。这是有限的,但大多数基本语法都得到支持。

{{#with getUser(id)?-}}
    Hello, {{#if isAdmin || isDev }}Mr. {{\if}}{{ user }}
{{/-with}}
Hello, {{#each conditions}}
    {{#-if let Some(check) = cond }}
        {{#-if check }}
            {{ let cond = if check { "&foo" } else { "&"} }}
            {{
                if check {
                    cond
                } else if let Some(cond) = key.cond {
                    if cond {
                        "1"
                    } else {
                        "2"
                    }
                } else {
                   "for"
                }
            }}
        {{- else if let Some(_) = cond }}
        {{- else if let Some(cond) = key.check }}
            {{#-if cond -}}
                baa
            {{/-if }}
        {{- else -}}
            {{ cond.is_some() }}
        {{/-if-}}
        {{ cond.is_some() && true }}
    {{-else if let Some(cond) = check }}
        {{#-if cond -}}
            bar
        {{/-if}}
    {{- else -}}
        None
    {{/-if
}}{{/each}}!
{{ let mut a = name.chars() }}

{{  
    let b: String = loop {
        if a.next().is_none() && true {
            let mut a = name.repeat(1);
            a.push('!');
            break a.repeat(2);
        } else {
            continue;
        }
    }
}}

{{ b }}
{{ let doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>() }}
{{ let doubled: Vec<usize> = a.iter().map(|x| x * 2).collect() }}

{{#each doubled -}}
    {{ key + 1 }}
{{/-each}}

路线图

  • 最小化文字中的html5
  • 生成定义的助手和过滤器的构建器
  • >|在fmt::Formatter上的过滤器
  • 在fmt::Formatter上连接过滤器,类似Unix,当可能时
  • ... 你可以打开一个issue!

依赖项

~16–30MB
~441K SLoC