Elementary: A modern and efficient HTML rendering library - inspired by SwiftUI, built for the web

Fact of the matter is that macros are computed at compile time, which offer significant performance improvement/efficiency over existing runtime-based html methods.

Test it yourself using my macro implementation: GitHub - RandomHashTags/swift-htmlkit: Write HTML using Swift Macros

with these testsin release mode:

func test_htmlkit() { measureElapsedTime(key: "htmlkit") { let _:String = #html([ #body([ #h1(["Swift HTML Benchmarks"]) ]) ]) } } func test_elementary() { measureElapsedTime(key: "elementary") { let _:String = html() { body() { h1() { "Swift HTML Benchmarks" } } }.render() } } func measureElapsedTime(key: String, _ block: () -> Void) { let duration:ContinuousClock.Duration = ContinuousClock().measure(block) print("measureElapsedTime;" + key + " took=\(duration)") } 

this arbitrary test producesat least on my machine (iMac 2019, Swift 6, macOS 15):

measureElapsedTime;elementary took=0.000146341 seconds measureElapsedTime;htmlkit took=1.04e-07 seconds 

146.341 microseconds vs 104 nanoseconds.

Comparing the two libraries, the macro implementation is 100x more efficient.
*I haven't tested it against Vapor's HTMLKit or Leaf, but they don't use macros, so they're probably slower too

3 Likes

This is really great and a promising approach.

Did you consider producing StaticString? Would that make further optimizations possible?

I haven't considered using StaticString, but I would assume it should offer a slight performance improvement. However it is worth noting that if you want to manipulate the compiled html during runtime you would need to convert it to a string manually. If I do go that approach I'll add some convenience logic to convert it easily.

A limitation right now is the implementation needs to do some string interpolation, which is not allowed for a StaticString, when assigning attributes with an enum value type or interpolated value. I am actively researching & testing workarounds.

Thanks so much for making this @sliemeobn, I also think that full stack Swift server apps with HTMX are a great way to get there. Whilst Swift Macros are powerful and seem like they could further increase performance (eventually though it could be negligible depending on the library usage), having a package with zero dependencies is priceless. Adding a small sponsorship for encouragement to keep going :innocent:

1 Like

@sliemeobn one question, would you have a suggestion on the best way to handle Elementary types inside raw html?
Pseudocode example:

HTMLRaw(""" ... existing html label(.for("name")) { "Enter your name:" } input(.type(.text), .name("name"), .autofocus) .roundedTextbox() ... existing html """) 

I guess I would wrap it in an Elementary element (or a HTMLBuilder function), like so:

div { HTMLRaw("...snippet 1...") label(.for("name")) { "Enter your name:" } input(.type(.text), .name("name"), .autofocus) .roundedTextbox() HTMLRaw("...snippet 2...") } 

you could also wrap the elementary bits in an element and call .render() I guess (but that'd be a bit less efficient), like so:

HTMLRaw(""" ... existing html \(MyElement().render()) ... existing html """) 
1 Like

Great suggestions, thanks a lot :folded_hands: