#server-side-rendering #leptos #wrapper #focused #upload #err #leptos-dom

nightly leptos_macabre

Horribly simple wrapper around leptos_dom, focused on server-side rendering

1 unstable release

0.1.0 Jan 16, 2024

#20 in #err

MIT license

34KB
199 lines

Leptos Macabre

Scary simple server-side rendering. Powered by Leptos.

use leptos_macabre::*;

let result: Result<_, &str> = Ok("Done!");
let style = "color: green;";

section! {
    h1!{ "Uploads" },
    match result {
        Ok(msg) => div! {
            @htmx-get="/uploads";
            @style;
            p!{ "Status: ", msg },
        },
        Err(err) => strong! {
            @class="error";
            "Uh Oh: " err
        },
    }
};

Syntax

  • Attributes starts with @ and end with ;.
  • Attributes Values are expressions returning impl leptos::IntoAttribute.
  • Attributes Values can be shorthanded when the name equals a variable in scope. Raw identifiers (i.e. r#type) are not supported.
  • Children are expressions returning impl leptos::IntoView.
  • Children can be delimited with an optional comma (helps rustfmt and auto-indenting, sometimes).

Details & Conveniences

Compile Time & Lsp

Due to everything being a minimally recursive macro_rules!, auto-complete and suggestions are incredibly snappy.

Auto .into_view()

Every macro in this crate returns a View, this intentionally diverts from leptos to not require .into_view() on each arm (an understandable requirement).

use leptos_macabre::*;
let result = Some(true);
let href = "#section";

match result {
    Some(true) => a!(@href; "Go here!"),
    Some(false) => p!(@class="bad"; "Uh-oh!"),
    None => div!(),
};

Every Element a Macro.

Each element is a separate macro. This saves many keystrokes. It is different from most Rust HTML macros.

use leptos::*;
use leptos_macabre::*;

view! { <button>"27 keystrokes"</button> }
button! { "10 keystrokes" }

Re-Export

This crate exports the leptos_dom items needed to work. If you just want to make HTML on the server, you can skip adding leptos as its own dependency.

Drawbacks

No reactivity that can't be implemented with a script! or normal html event handlers. No signals. Performance will probably be worse when compared directly to leptos::view!.

leptos components with props are minimally supported. The generated Prop* struct would need to be provided as an argument, meaning you skip many of the conveniences of using #[component] in the first place (optional props etc).

use leptos_macabre::*;
use leptos::component;

#[component]
fn MyButton() -> impl leptos::IntoView {}

#[component]
fn MyA(href: &'static str) -> impl leptos::IntoView {}

p!{ MyButton };
p!{ MyButton() };
p!{ MyA(MyAProps { href: "#red" }) };

Since children are just expressions returning impl IntoView, you can swap out components with boring old functions.

use leptos_macabre::*;

fn my_button() -> impl leptos::IntoView { }
fn my_a(href: &'static str) -> impl leptos::IntoView {}
fn my_b(inner: Option<bool>) -> impl leptos::IntoView {}

div! { 
    my_button,
    my_button(),
    my_a("#red"),
    my_b(Some(true)) ,
};

Name

I always thought the horrorshow crate was neat, and leptos is close to the disease leptospirosis. It is all just a little grim. Secondly, this crate is created with nested macro_rules!, something truly horrendous.

Dependencies

~14–28MB
~415K SLoC