2 unstable releases
0.2.0 | Mar 22, 2024 |
---|---|
0.1.1 | Mar 7, 2024 |
0.1.0 |
|
#191 in Template engine
136 downloads per month
23KB
215 lines
HTML Compile
A template engine for generating HTML strings within Rust for use with static websites.
HTML strings can be generated by inputting a concise syntax into provided macros or, alternatively, from Rust structs.
This engine prioritizes speed and should only be used with trusted HTML data.
Generating HTML using Macros
A complete example is provided on GitHub in the directory example. The below provides an explanation of different aspects of the syntax.
The syntax used is inspired by pug.js but has been adapted to better fit use within a Rust context.
Creating a Text Element
Using a String Literal
html!(div (style = "border: 1px solid black;" class = "Hello") "Hello World");
Will create the following string of HTML that consists of a div
with a style
attribute that creates a black border, a class
attribute set to Hello
and text set to "Hello World"
"<div style=\"border: 1px solid black;\" class=\"Hello\">Hello World</div>"
The first token (here div
) specifies the name of the element.
The set of parentheses ()
contains the attributes for the element. The attribute name comes before the =
and the attribute value after and is in double quotation marks. Different attributes are separated by whitespace.
The text in double quotation marks at the end of the content specifies the text content "Hello World"
.
Using a Variable
The text can also be derived from a variable. In this case surround the variable with curly brackets {}
let example_text = "Hello World";
html!(div (style = "border: 1px solid black;" class = "Hello") {example_text});
gives the same result as before:
"div style=\"border: 1px solid black;\" class=\"Hello\">Hello World</div>"
Creating an Element with No Attributes or Content
Both html!(div)
and html!(div ())
will create a string of HTML consisting of an empty div with no styling
"<div></div>"
Void elements should not have end tags and this is handled accordingly. For example html!(hr)
will return "<hr />"
Creating Elements that Contain other Elements
html!(ul () [el!(li () "First Sibling")] [el!(li () "Second Sibling")])
Will create the following string of HTML that consists of an unordered list with two items
"<ul><li>First Sibling</li><li>Second Sibling</li></ul>"
In the browser this renders as
- First Sibling
- Second Sibling
Each child component is surrounded by square brackets []
and is inputted into the macro el!
which creates the component. Multiple specified child components are treated as siblings.
The result from el!(li () "Second Sibling")
could have been stored in a variable and the variable used instead as follows:
let second_sibling = el!(li () "Second Sibling");
let result = html!(ul()[el!(li () "First Sibling")][second_sibling]);
This would return the same HTML String.
Where Child Elements are Specified through a Vector or an Array
let example_list = [
el!(li () "First Sibling"),
el!(li () "Second Sibling")
];
html!(ul () vec[example_list])
Will create the following string of HTML that consists of an unordered list with two items
"<ul><li>First Sibling</li><li>Second Sibling</li></ul>"
In the browser this renders as
- First Sibling
- Second Sibling
Inserting the text vec
before the square brackets []
tells the macro to expect a vector or array.
Generating HTML using Rust structs
This library also provides tooling that enables generating HTML strings from Rust structs using the function build_component()
.
use std::fs;
fn main() {
use html_compile::compile::*;
use html_compile::types::*;
let item_list: Vec<String> = vec![1, 2, 3].iter().map(|x| format!("{}", x)).collect();
let item_components: Vec<Box<Component>> = item_list
.iter()
.map(|item| {
Box::new(Component {
tag: "li",
meta: None,
child: Child::Text(item),
})
})
.collect();
let input_component = Component {
tag: "section",
meta: Some(vec![
Attribute {
label: "class",
value: "Example",
},
]),
child: Child::ComponentVec(vec![
Box::new(Component {
tag: "h2",
meta: None,
child: Child::Text("A List of Items"),
}),
Box::new(Component {
tag: "p",
meta: None,
child: Child::Text("The list begins after the following line"),
}),
Box::new(Component {
tag: "hr",
meta: None,
child: Child::NoChild,
}),
Box::new(Component {
tag: "ul",
meta: None,
child: Child::ComponentVec(item_components),
}),
]),
};
let output = build_component(&input_component);
let write_output_path = "./output.html";
fs::write(write_output_path, output).expect("Unable to write to file");
}
The file output.html
looks like the following:
<section class="Example">
<h2>A List of Items</h2>
<p>The list begins after the following line</p><hr/><ul><li>1</li><li>2</li><li>3</li></ul>
</section>
This will render in the browser as follows:
A List of Items
The list begins after the following line
- 1
- 2
- 3
Inserting HTML into existing HTML string
html_compile provides a macro insert_html!
and function insert_components
that searches for the placeholder string {COMPONENT}
and switches this for the HTML string generated.
macro
insert_html!({test_contents}, div () "Hello World")
function
let test_component: Component = Component {
tag: "div",
meta: None,
child: Child::Text("Hello World"),
};
insert_components(test_contents, test_component)
Both search the String
in the variable test_contents
for the placeholder {COMPONENT}
and swap the placeholder for <div>Hello World</div>
.
Find in crates.io
Find code on GitHub
Note that in the code on GitHub there is a directory example
that provides an example application using this library.