54 lines
1.8 KiB
Markdown
54 lines
1.8 KiB
Markdown
|
# HTML templating language
|
||
|
A common task with HTML is creating 'templates', or reusable components
|
||
|
that are stitched together to form a complete document. Front end frameworks
|
||
|
typically achieve this through scripting on the client. I prefer instead to
|
||
|
generate static HTML files on the server. To this end, I wrote my own templating
|
||
|
engine. It parses HTML source and template files, and produces output files which
|
||
|
are minified and with CSS and JavaScript inlined. Additional post processing can
|
||
|
be performed, like syntax highlighting for code blocks.
|
||
|
|
||
|
Existing Rust for parsing HTML use recursive descent, outputting a tree
|
||
|
data structure. I prefer flat data structures and linear algorithms, and so
|
||
|
I wrote my own parser.
|
||
|
|
||
|
```rust
|
||
|
// My lexeme type (fields omitted)
|
||
|
pub enum HtmlElement {
|
||
|
DocType,
|
||
|
Comment (...),
|
||
|
OpenTag {...},
|
||
|
CloseTag {...},
|
||
|
Text (...),
|
||
|
Script {...},
|
||
|
Style {...},
|
||
|
Directive {...},
|
||
|
}
|
||
|
```
|
||
|
Lexemes are stored in a flat array. Tags are consumed by taking a slice of
|
||
|
the array from the opening tag until the closing tag. Expanding a template
|
||
|
is done by simply copying its contents into the array. Directives, prefixed
|
||
|
with an @ can pass properties and child nodes to a template.
|
||
|
```html
|
||
|
<!-- This is a template definition -->
|
||
|
<Demo>
|
||
|
<h1 id=@prop_name>
|
||
|
<@children>
|
||
|
</h1>
|
||
|
</Demo>
|
||
|
|
||
|
<!-- This is a template instantiation -->
|
||
|
<Demo prop_name="something">
|
||
|
<i> Hello World! </i>
|
||
|
</Demo>
|
||
|
|
||
|
<!-- This is how the template gets expanded -->
|
||
|
<h1 id="something"/>
|
||
|
<i> Hello World! </i>
|
||
|
</h1>
|
||
|
```
|
||
|
The templating engine is free-standing by default, but optionally integrates
|
||
|
with Tree Sitter to highlight and format code blocks. To do this I use
|
||
|
the [inkjet](https://crates.io/crates/inkjet) and
|
||
|
[v_htmlescape](https://crates.io/crates/v_htmlescape) crates.
|
||
|
|