A Rust webes ökoszisztémája az elmúlt két évben rohamosan fejlődött, és a Leptos az egyik olyan projekt, amit egyszerűen nem lehet kihagyni, ha valaki full-stack Rust webfejlesztésről beszél. Ma jelent meg a 0.5-ös verzió, és őszintén szólva ez az egyik legjelentősebb frissítés, amit a keretrendszer eddig kapott.
Mi az a Leptos, és miért fontos?
A Leptos egy reaktív, WebAssembly-alapú frontend framework, amely ugyanazt a komponens-modellt használja szerver- és kliensoldalon is – innen a "full-stack" jelző. A cél, hogy egyetlen Rust kódbázisból generálódjon a szerveroldali HTML (SSR), a hidratáció, és a kliensoldali interaktivitás is, anélkül, hogy JavaScript-re vagy külön API-rétegre lenne szükség.
Azért fontos ez, mert a Rust közösségben eddig két nagy irányzat versengett: a virtuális DOM-ot használó megoldások (mint a Yew), és a signal-alapú, finomszemcsés reaktivitást választó projektek. A Leptos az utóbbi táborba tartozik, és a SolidJS-hez hasonló architektúrát ültet át Rust nyelvre.
Ha még nem találkoztál a Leptos-szal: gondolj rá úgy, mint egy Rust-os SolidJS-re, ahol a view! makró generálja a DOM-manipulációs kódot fordási időben, virtuális DOM nélkül.
A 0.5-ös verzió legfontosabb újításai
A Leptos csapata a 0.5-ös kiadásban több hónapos munka eredményét tette közzé. A legfontosabb változások:
- Teljesen újraírt reaktivitási rendszer, amely most már finomabb granularitású frissítéseket tesz lehetővé
- Server function makrók stabilizálása, amivel a kliens és szerver közötti hívások írása sokkal egyszerűbb
- Jobb hidratációs teljesítmény, kevesebb felesleges DOM-összehasonlítással
- Axum és Actix integráció frissítése, mostantól kényelmesebb a routing beállítása
Egy egyszerű komponens így néz ki a 0.5-ös API-val:
use leptos::*;
#[component]
fn Counter(initial_value: i32) -> impl IntoView {
let (count, set_count) = create_signal(initial_value);
view! {
<button on:click=move |_| set_count.update(|n| *n += 1)>
"Kattints ide: " {count}
</button>
}
}
Ami elsőre furcsa lehet a Yew-hoz vagy React-hoz szokott fejlesztőknek: itt nincs re-render a komponens szintjén. A count signal olvasása a view! makróban egy célzott DOM-frissítést regisztrál, ami csak azt az egy szöveges node-ot érinti, ami valóban megjelenik.
Reaktivitási modell és teljesítmény
A Leptos reaktivitási modellje a create_signal, create_memo és create_effect hármasára épül. Ezek a signal-alapú primitívek egy dependency gráfot tartanak fenn futásidőben, és amikor egy signal értéke megváltozik, csak azok a részek frissülnek, amelyek tényleg függenek tőle.
use leptos::*;
fn main() {
let (name, set_name) = create_signal("Rust".to_string());
// A memo csak akkor számol újra, ha a name valóban változik
let greeting = create_memo(move |_| format!("Szia, {}!", name.get()));
create_effect(move |_| {
leptos::logging::log!("{}", greeting.get());
});
set_name.set("Leptos".to_string());
}
A 0.5-ös verzióban a csapat kifejezetten a memo-k és effect-ek ütemezését optimalizálta: a korábbi verziókban előfordultak felesleges újraszámolások, amikor egy signal többszörösen frissült egyetlen "tick" alatt. Most ezek batch-elve futnak, ami mérhetően csökkenti a CPU-terhelést nagyobb komponensfákban.
Ha a projektedben sok egymásba ágyazott create_memo hívást használsz, érdemes megmérni a régi és az új verzió közti különbséget – a csapat blogbejegyzése szerint egyes benchmarkokban 30-40%-os gyorsulást is mértek.
A teljesítmény szempontjából érdemes megemlíteni, hogy a Leptos build-je erősen támaszkodik a fordítási idejű makró-expanzióra. A view! makró nem futásidőben parsz-olja a JSX-szerű szintaxist, hanem közvetlenül Rust kódra fordítja, ami a WebAssembly bundle méretét is kedvezően érinti.
Server-side rendering és hidratáció finomítások
Az SSR és hidratáció mindig a legkényesebb rész egy izomorf keretrendszerben, és a Leptos 0.5 itt is jelentős előrelépést hozott. A hidratáció során a szerver által legenerált HTML-t a kliens oldali WASM kód "felveszi", és rákapcsolja a reaktív event listenereket – anélkül, hogy a teljes DOM-ot újra kellene építeni.
A korábbi verziókban ez a folyamat time-to-interactive szempontból nem volt optimális nagyobb oldalaknál, mert a hidratáció szinkron módon, egyben futott le. A 0.5-ben bevezetett out-of-order streaming támogatás lehetővé teszi, hogy a szerver darabokban (chunk) küldje a HTML-t, és a kliens fokozatosan hidratáljon.
Egy egyszerű Axum-alapú szerver integráció így nézhet ki:
use axum::{routing::get, Router};
use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
#[tokio::main]
async fn main() {
let conf = get_configuration(None).await.unwrap();
let leptos_options = conf.leptos_options;
let addr = leptos_options.site_addr;
let routes = generate_route_list(App);
let app = Router::new()
.leptos_routes(&leptos_options, routes, App)
.fallback(leptos_axum::file_and_error_handler)
.with_state(leptos_options);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
#[component]
fn App() -> impl IntoView {
view! { <h2>"Üdv a Leptos SSR alkalmazásban!"</h2> }
}
Az Axum integráció API-ja a 0.4-ről 0.5-re migrálva néhány helyen módosult, például a generate_route_list szignatúrája. Ha frissítesz egy meglévő projektet, olvasd át a changelogot, mielőtt fejest ugrasz a build hibák debuggolásába.
Hogyan viszonyul a Leptos más Rust web frameworkökhöz?
A Rust WASM-alapú frontend keretrendszerek mezőnyében ma három komoly szereplő van: Yew, Dioxus és Leptos. A Yew a legrégebbi és legstabilabb, virtuális DOM-mal dolgozik, és React-szerű mentális modellt ad. A Dioxus hasonló elveket követ, de erős fókuszt tesz a multi-platform (desktop, mobil) használatra is. A Leptos ezzel szemben tudatosan elhagyja a virtuális DOM-ot, és a signal-alapú finomszemcsés reaktivitásra épít – ez különösen nagy, adatintenzív felületeken hoz mérhető teljesítménybeli előnyt.
Ha a backend oldalt nézzük, a Leptos nem versenyzik közvetlenül olyan tiszta API keretrendszerekkel, mint az Axum vagy az Actix Web – sőt, épp ezekre épül rá az SSR réteg. Aki tehát ma egy klasszikus REST API-t akar építeni, továbbra is jól teszi, ha közvetlenül az Axum 0.6-ot választja. Aki viszont egy teljes, interaktív felhasználói felületet szeretne egyetlen Rust kódbázisból, annak a Leptos egyre komolyabb alternatívát kínál a JavaScript-alapú full-stack keretrendszerekkel (Next.js, Remix) szemben.
A Leptos 0.5 még mindig aktívan fejlődő projekt, az API egyes részei (különösen a server function makrók körüli finomságok) a jövőben is változhatnak. Production環境ben érdemes fixálni a verziót a Cargo.toml-ban, és óvatosan frissíteni.
Összefoglalás
A Leptos 0.5 nem csak egy inkrementális frissítés – a reaktivitási motor újraírása, a hidratáció finomítása és az Axum integráció érettebbé válása mind abba az irányba mutat, hogy a Rust full-stack webfejlesztés lassan kikerül a "kísérleti" kategóriából. Ha eddig csak távolról figyelted a projektet, most van itt az ideje, hogy kipróbáld egy kisebb side projecten – a tanulási görbe meredek lehet, de a végeredmény egy típusbiztos, gyors és valóban egységes Rust kódbázis frontendre és backendre egyaránt.