mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 11:04:40 -05:00
feat: #[island(lazy)]
This commit is contained in:
@@ -19,6 +19,7 @@ use syn::{
|
||||
|
||||
pub struct Model {
|
||||
is_transparent: bool,
|
||||
is_lazy: bool,
|
||||
island: Option<String>,
|
||||
docs: Docs,
|
||||
unknown_attrs: UnknownAttrs,
|
||||
@@ -66,6 +67,7 @@ impl Parse for Model {
|
||||
|
||||
Ok(Self {
|
||||
is_transparent: false,
|
||||
is_lazy: false,
|
||||
island: None,
|
||||
docs,
|
||||
unknown_attrs,
|
||||
@@ -140,6 +142,7 @@ impl ToTokens for Model {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
is_transparent,
|
||||
is_lazy,
|
||||
island,
|
||||
docs,
|
||||
unknown_attrs,
|
||||
@@ -530,15 +533,38 @@ impl ToTokens for Model {
|
||||
};
|
||||
|
||||
let hydrate_fn_name = hydrate_fn_name.as_ref().unwrap();
|
||||
quote! {
|
||||
#[::leptos::wasm_bindgen::prelude::wasm_bindgen(wasm_bindgen = ::leptos::wasm_bindgen)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn #hydrate_fn_name(el: ::leptos::web_sys::HtmlElement) {
|
||||
#deserialize_island_props
|
||||
let island = #name(#island_props);
|
||||
let state = island.hydrate_from_position::<true>(&el, ::leptos::tachys::view::Position::Current);
|
||||
// TODO better cleanup
|
||||
std::mem::forget(state);
|
||||
|
||||
let hydrate_fn_inner = quote! {
|
||||
#deserialize_island_props
|
||||
let island = #name(#island_props);
|
||||
let state = island.hydrate_from_position::<true>(&el, ::leptos::tachys::view::Position::Current);
|
||||
// TODO better cleanup
|
||||
std::mem::forget(state);
|
||||
};
|
||||
if *is_lazy {
|
||||
let outer_name =
|
||||
Ident::new(&format!("{name}_loader"), name.span());
|
||||
|
||||
quote! {
|
||||
#[::leptos::prelude::lazy]
|
||||
#[allow(non_snake_case)]
|
||||
async fn #outer_name (el: ::leptos::web_sys::HtmlElement) {
|
||||
#hydrate_fn_inner
|
||||
}
|
||||
|
||||
#[::leptos::wasm_bindgen::prelude::wasm_bindgen(wasm_bindgen = ::leptos::wasm_bindgen)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn #hydrate_fn_name(el: ::leptos::web_sys::HtmlElement) {
|
||||
::leptos::task::spawn_local(#outer_name(el))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#[::leptos::wasm_bindgen::prelude::wasm_bindgen(wasm_bindgen = ::leptos::wasm_bindgen)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn #hydrate_fn_name(el: ::leptos::web_sys::HtmlElement) {
|
||||
#hydrate_fn_inner
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -610,6 +636,13 @@ impl Model {
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn is_lazy(mut self, is_lazy: bool) -> Self {
|
||||
self.is_lazy = is_lazy;
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn with_island(mut self, island: Option<String>) -> Self {
|
||||
self.island = island;
|
||||
|
||||
@@ -560,7 +560,7 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
false
|
||||
};
|
||||
|
||||
component_macro(s, is_transparent, None)
|
||||
component_macro(s, is_transparent, false, None)
|
||||
}
|
||||
|
||||
/// Defines a component as an interactive island when you are using the
|
||||
@@ -637,36 +637,37 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
#[proc_macro_attribute]
|
||||
pub fn island(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
let is_transparent = if !args.is_empty() {
|
||||
let transparent = parse_macro_input!(args as syn::Ident);
|
||||
let (is_transparent, is_lazy) = if !args.is_empty() {
|
||||
let arg = parse_macro_input!(args as syn::Ident);
|
||||
|
||||
if transparent != "transparent" {
|
||||
if arg != "transparent" && arg != "lazy" {
|
||||
abort!(
|
||||
transparent,
|
||||
"only `transparent` is supported";
|
||||
help = "try `#[island(transparent)]` or `#[island]`"
|
||||
arg,
|
||||
"only `transparent` or `lazy` are supported";
|
||||
help = "try `#[island(transparent)]`, `#[island(lazy)]`, or `#[island]`"
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
(arg == "transparent", arg == "lazy")
|
||||
} else {
|
||||
false
|
||||
(false, false)
|
||||
};
|
||||
|
||||
let island_src = s.to_string();
|
||||
component_macro(s, is_transparent, Some(island_src))
|
||||
component_macro(s, is_transparent, is_lazy, Some(island_src))
|
||||
}
|
||||
|
||||
fn component_macro(
|
||||
s: TokenStream,
|
||||
is_transparent: bool,
|
||||
is_lazy: bool,
|
||||
island: Option<String>,
|
||||
) -> TokenStream {
|
||||
let mut dummy = syn::parse::<DummyModel>(s.clone());
|
||||
let parse_result = syn::parse::<component::Model>(s);
|
||||
|
||||
if let (Ok(ref mut unexpanded), Ok(model)) = (&mut dummy, parse_result) {
|
||||
let expanded = model.is_transparent(is_transparent).with_island(island).into_token_stream();
|
||||
let expanded = model.is_transparent(is_transparent).is_lazy(is_lazy).with_island(island).into_token_stream();
|
||||
if !matches!(unexpanded.vis, Visibility::Public(_)) {
|
||||
unexpanded.vis = Visibility::Public(Pub {
|
||||
span: unexpanded.vis.span(),
|
||||
@@ -674,6 +675,7 @@ fn component_macro(
|
||||
}
|
||||
unexpanded.sig.ident =
|
||||
unmodified_fn_name_from_fn_name(&unexpanded.sig.ident);
|
||||
|
||||
quote! {
|
||||
#expanded
|
||||
|
||||
|
||||
Reference in New Issue
Block a user