4 个版本

0.1.3 2022年8月22日
0.1.2 2022年8月21日
0.1.1 2022年8月6日
0.1.0 2022年8月6日

网页开发 中排名 1935

MIT 许可证

125KB
3K SLoC

mini-builder-rs

静态网站生成器。

编程语言使用函数来避免重写类似的逻辑。HTML 没有这样的功能。此包提供了一种可以插入到 HTML(或任何)文件中的简单语言,以便以编程方式生成新文件。

例如,考虑以下 HTML

<section>
    <a href="page 1" class="selected">Page1</a>  
    <a href="page 2" class="">Page2</a>  
    <a href="page 3" class="">Page3</a>  
</section>

如果没有静态网站生成器,这个 HTML 片段就必须复制并粘贴到每个页面,并对 a 标签将具有 selected 类的微小更改。然而,使用静态网站生成器,这个片段可以存储在文件中,例如 navigation.html,然后在每个页面上重复使用。例如

navigation.html

<section>
    <a href="page 1" class="{{ if page == 'page 1' ? 'selected' : ''}}">Page1</a>  
    <a href="page 2" class="{{ if page == 'page 2' ? 'selected' : ''}}">Page2</a>  
    <a href="page 3" class="{{ if page == 'page 3' ? 'selected' : ''}}">Page3</a>  
</section>

page1.html

...
{{@ navigation(page = 'page 1')}}
...

示例

有关一些代码示例,请查看 examples 目录。

构建器

Builder 处理

mini_builder_rs::builder::Builder::new(
	// sources - the source for the pages that will be generated
	Some("./examples/example_site/sources".into()),
	// templates - the partial files that can be referenced
	//             from sources or other templates
	Some("./examples/example_site/templates".into()),
	// generated - where the transformed sources will be placed
	Some("./examples/example_site/generated".into()),
	// variables - a file containing global variables and their values
	Some("./examples/example_site/variables".into()),
	// see mini_builder_rs::builder::BuilderOptions
	Default::default(),
)
.unwrap()
// variable that will be available for every source and template
// (unless shadowed)
.add_variable("title", Value::text("Website Title"))
.add_variable(
	"files",
	Value::List(DATA.iter().map(|x| Value::text(x.0)).collect::<Vec<_>>()),
)
// functions that can be called from every source and template
.add_function("get_file_size", Box::new(get_file_size) as _)
// watch for changes in the sources and templates directories,
// updating the generated directory live
.watch()
.unwrap();

...

fn get_file_size(values: &[Value]) -> Value {
    if let Some(Value::Text(name)) = values.get(0) {
        for (file_name, file_size) in DATA {
            if file_name == name {
                return Value::Number(*file_size);
            }
        }
    }
    Value::None
}

资源和模板

资源对应于输出文件。模板是用于生成文本的资源或模板。例如,如果资源是 page_1.htmlpage_2.html,模板是 navigation.htmlfooter.html,则网站完成后的输出将是仅 page_1.htmlpage_2.html 的展开版本。

模板使用以下语法调用:@ template(key1 = value1, ...)

模板的名称可以是显式地给定作为字符串,也可以是在从文件加载时相对于模板目录的文件路径(忽略扩展名)(例如,模板 template/sub_dir1/temp1.html 的名称将是 sub_dir1/tmp1)。

变量和函数

使用以下枚举定义值

pub enum Value {
    Number(f32),
    Bool(bool),
    Text(String),
    List(Vec<Value>),
    None,
}

函数通过类型定义:Box<dyn Fn(&[Value]) -> Value + 'static>

指令

指令是一段具有以下模式的代码:{{...}},它为普通文件添加逻辑。如 if 语句这样的控制流指令使用略有不同的模式:{{# ...}}。指令内部使用的语言可以通过以下几个例子总结:

  • 表达式
<!-- if the variables `a` and `b` are defined, they will be added and returned
-->
<p> a + b = {{ a + b }} </p>
  • 如果语句
{{# if page == 'page 1' }}
    <!-- if the variable `page` exists and equals to 'page 1' this section will
	be evaluated  -->
    ...
{{# elif page == 'page 2'}}
    <!-- elif is short for else if -->
    ...
{{# else }}
    ....
{{#}}
  • for 循环
<!-- the for each loop will be evaluated if the variable `files` exists and is
a list -->
{{# for file in files}}
    <h2>{{ file }}</h2>
{{#}}
  • 三元运算符
{# if a != None && b != None}}
    <p>a is{{ a > b ? 'greater than : a < b ? 'smaller than' : 'equals to'}} b</p>
{{# else}}
    <p>a or b are none</p>
{{#}}
  • 模板
<!-- Templates are not control flow, they are expressions and therefore can be
with other expressions. if no variables are passed to a template then both the
syntaxes `@ template` and `@ template()` are valid. -->
{{ use_pretty_header ? @ pretty_header : @ normal_header}}

<!-- call the `footer` template with a single variable called
`use_pretty_footer` whose value equals to the variable `use_pretty_header`
value's -->
{{@ footer(use_pretty_footer = use_pretty_header)}}

依赖关系

~3–12MB
~111K SLoC