Replacing Leaf with a Swift DSL

When Apple revealed SwiftUI last week during WWDC 2019, we also saw a new feature in Swift proposed as a draft on Swift Evolution (Function builders). Together with the Property wrappers proposal and some other recent Swift features, in Swift 5.1 it will be now possible to define DSLs that will enable code like this (screenshot from this WWDC session):


Yes, this is Swift code!

As you can see, it will soon be possible to natively support HTML by implementing a DSL for it in Swift (like Vaux does) with all the advantages that come along with it: Great compiler errors as feedback, autocompletion, more readable and flexible functions, Swift-native control flow etc.

While Leaf is a good template engine, I think it would make sense to introduce an alternative to Leaf based on such a DSL for HTML, CSS and the likes of it. What do you guys think?

9 Likes

As a heavy user of templating languages, I'd be all for this. However, I do hope this will become a SSWG effort, so we don't end up with multiple incompatible DSLs.

FYI: There's also GitHub - pointfreeco/swift-html: 🗺 A Swift DSL for type-safe, extensible, and transformable HTML documents.. I believe pointfree uses this for their website.

7 Likes

I know of swift-html, but it doesn't use the new features in Swift (cause they weren't announced at that time) and the dot syntax they're using is much less powerful then what will be possible with Swift 5.1 onwards. Note that with the new DSL you won't even need commas between statements!

1 Like

I think GitHub - vapor-community/HTMLKit: Create and render HTML templates with HTMLKit would be a great place to implement function builder support.

Depending on how the HTMLKit package is received, the core team would consider making it an official package (moving it to vapor/*) and offering it during vapor new project initialization.

1 Like

:wave: Hi! One of the swift-html developers here.

Point-Free's swift-html library offers a DSL vision from before the era of "function builders". Because of this it doesn't (and couldn't) take advantage of the new, implicit syntax that function builders offers, but it's definitely not "less" powerful! If anything it's "differently" (and sometimes more) powerful. We want to explore what the Swift DSL syntax has to offer, and we plan on updating our libraries accordingly, but please understand that function builders introduce limited sugar on top of existing means of building DSLs in Swift.

The swift-html library lets you build HTML as first-class Swift values, which means arrays of non-HTML values can be mapped to arrays of li elements using the map that comes with Sequence. Function builders can't take advantage of these operations and instead requires custom ForEach operators to be defined per DSL.

In the end, function builders are an early work in progress, and even though they read very nicely, they are much less composable right now. A few folks have pointed this out in evolution, so if this kind of flexibility is important to you, now's a good time to weigh in!

10 Likes

Something like SwiftWebUI?

3 Likes

I really like the idea of moving to a DSL. I have wondered how one would integrate some basic Javascript functionality for things like disabling buttons when all the required fields are not full, or client-side validation. There are many cases were a bit of interactivity would be all that was needed, not a full single page application.

@MajorTom have you tried using something like HTMLKit? That's a fairly straight-forward thing to support right now.

Leaf falls apart if you try to do anything with in-page HTML script blocks.

I looked briefly at both HTMLKit and Swift-HTML (with the Vapor version), and was not really clear how I would add the JavaScript. It is probably easy, but I did not see how I would do it. :slight_smile:

I can't check right now but as far as I know, HTMLKit has a Builder that would allow you to do something like:

Script {
"""
// Write your JS here.
"""
}

I did not find script as one of the tags they generate, but I may have missed it.

FWIW this now exists too GitHub - JohnSundell/Plot: A DSL for writing type-safe HTML, XML and RSS in Swift.

3 Likes

I don’t think Sundell’s repo uses the DSL @Builder or @functionBuilder though.

A bit late to the party, but wanted to point out that out of all of the options mentioned here, SwiftWebUI seems to be using a proper DSL (fairly well implemented imho) to render SwiftUI looking code into HTML/CSS, but most importantly it will also bind back actions.
The following is what you write, ie: the SwiftUI looking code.

// Note that The View here is a SwiftWebUI.View rather than a SwiftUI.View
// but this makes reading this code fairly trivial
struct OrderPage: View {
    @State var order = Order()

    var body: some View {
        Form {
            Section {
                Stepper(value: $order.quantity, in: 1...10) {
                    Text("Quantity: \(order.quantity)")
                }
            }
        }.padding()
    }
}

Their example of the AvocadoToast does a fantastic job of building a proper web application.
Which none of the other choices mentioned come close.

1 Like