feat(wasm): execute client handlers without requests

req: client_local/001\nreq: client_local/004\nreq: client_local/005\nreq: client_local/009\nreq: client_local/010\nreq: client_local/014\nreq: v1_release/001
This commit is contained in:
slhx agent
2026-07-13 12:33:54 +02:00
parent 0d49007c61
commit 40643e360d
16 changed files with 515 additions and 25 deletions
+8 -1
View File
@@ -10,7 +10,14 @@ path = "src/lib.rs"
name = "render"
harness = false
[features]
default = []
client = ["dep:hemx-wasm"]
[dependencies]
hemplate = { path = "../../hemplate/hemplate" }
hemx-core = { path = "../hemx-core" }
hemx-derive = { path = "../hemx-derive" }
hemx-wasm = { path = "../hemx-wasm", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
hemplate = { path = "../../hemplate/hemplate" }
+19 -1
View File
@@ -3,7 +3,9 @@
//! Most application code should depend on this crate, use the proc-macros from
//! here, and import generated resources through `#[hemx::surface]`.
use hemx_core::{Effect, KeyedSlot, SafeHtml, Slot};
use hemx_core::SafeHtml;
#[cfg(not(target_arch = "wasm32"))]
use hemx_core::{Effect, KeyedSlot, Slot};
pub use hemx_core::{
navigate, push, redirect, replace, CssClass, CssClasses, Form, FormContract, FormControlKind,
@@ -19,6 +21,14 @@ pub use hemx_core::{
pub use hemx_core::{Atom, ComponentRef, EventName, GeneratedTarget, Handle, ParamName};
pub use hemx_derive::{app, component, form, handler, surface};
/// Browser/WASM integration used by `#[hemx::handler(client)]`.
///
/// The feature is opt-in so server-first applications do not compile or ship
/// WASM dependencies. req: client_local/001 req: client_local/004
#[cfg(feature = "client")]
#[doc(hidden)]
pub use hemx_wasm as wasm;
/// Advanced/raw hemx primitives used by generated code, integrations, and tests.
///
/// Beginner-facing application code should prefer generated targets, generated
@@ -26,6 +36,7 @@ pub use hemx_derive::{app, component, form, handler, surface};
pub mod advanced {
pub use hemx_core::*;
#[cfg(not(target_arch = "wasm32"))]
pub fn render(view: &impl hemplate::Hemplate) -> crate::Html {
crate::render_template(view)
}
@@ -79,6 +90,7 @@ pub mod __private {
}
}
#[cfg(not(target_arch = "wasm32"))]
fn render_template(view: &impl hemplate::Hemplate) -> Html {
let mut html = String::with_capacity(view.size_hint());
view.render_into(&mut html)
@@ -86,6 +98,7 @@ fn render_template(view: &impl hemplate::Hemplate) -> Html {
__private::html_trusted(html)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn page(view: &impl hemplate::Hemplate) -> Html {
render_template(view)
}
@@ -99,6 +112,7 @@ pub trait KeyedPartial {
fn hemx_key(&self) -> String;
}
#[cfg(not(target_arch = "wasm32"))]
#[doc(hidden)]
pub fn render_html(view: &impl hemplate::Hemplate) -> Html {
render_template(view)
@@ -108,6 +122,7 @@ pub fn render_html(view: &impl hemplate::Hemplate) -> Html {
///
/// Prefer generated target objects such as `targets::list.put(&view)` so
/// generated resource lowering stays attached to the view boundary. req: dx/006
#[cfg(not(target_arch = "wasm32"))]
#[doc(hidden)]
pub trait RenderSlotExt {
fn render(self, view: &impl hemplate::Hemplate) -> Effect;
@@ -120,6 +135,7 @@ pub trait RenderSlotExt {
}
}
#[cfg(not(target_arch = "wasm32"))]
impl<T> RenderSlotExt for Slot<T> {
fn render(self, view: &impl hemplate::Hemplate) -> Effect {
self.html(render_template(view))
@@ -130,6 +146,7 @@ impl<T> RenderSlotExt for Slot<T> {
///
/// Prefer generated target objects such as `targets::row.append(&view)` so
/// generated resource lowering stays attached to the view boundary. req: dx/006
#[cfg(not(target_arch = "wasm32"))]
#[doc(hidden)]
pub trait RenderKeyedSlotExt<K> {
fn append(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
@@ -158,6 +175,7 @@ pub trait RenderKeyedSlotExt<K> {
}
}
#[cfg(not(target_arch = "wasm32"))]
impl<K, T> RenderKeyedSlotExt<K> for KeyedSlot<K, T>
where
K: ToString,