leptos-rs / leptos

Build fast web applications with Rust.
https://leptos.dev
MIT License
16.41k stars 656 forks source link

Public leptos_meta::register function #3230

Open luoxiaozero opened 1 week ago

luoxiaozero commented 1 week ago

Is your feature request related to a problem? Please describe.

Currently I inject css into head via Style in SSR mode, and control css via custom logic in Hydrate mode.

fn mount_style(id: &str, content: &'static str) {
    if #[cfg(feature = "ssr")] {
        let _ = view! {
            <Style id=id>
                {content}
            </Style>
        };
    } else {
        let head = document().head().expect("head no exist");
        let style = head
            .query_selector(&format!("style#{id}"))
            .expect("query style element error");
        if style.is_some() {
            return;
        }
        let style = document()
            .create_element("style")
            .expect("create style element error");
        _ = style.set_attribute("id", &id);
        style.set_text_content(Some(content));
        _ = head.prepend_with_node_1(&style);
    }
}

When I hydrate via the following code, <Style>". b {}"</Style> gets hydrated to the <style>". a{}"</style> element instead of the <style>". b{}"</style> element.

#[component]
pub fn Button() -> impl IntoView {
    mount_style("button", ".a {}");
    view! {
        <Style>
             ".b {}"
         </Style>
    }
}

Describe the solution you'd like

Public leptos_meta::register function. Allows passing a second parameter to control the position of the generated HTML string to avoid hydration.

pub fn register<E, At, Ch>(
    el: HtmlElement<E, At, Ch>,
    config: RegisterConfig,
) -> RegisteredMetaTag<E, At, Ch>

pub struct RegisterConfig {
    position: ElementPosition
}

pub enum ElementPosition {
    // Before the <!--HEAD--> comment.
    MarkerBefore,
    // After the <!--HEAD--> comment.
    MarkerAfter,
}

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context

RegisterConfig is a struct in order to expand more fields in the future to achieve the same functions as unhead.

gbj commented 1 week ago

It seems like there are multiple people interested in having the ability to inject things into the <head> where leptos_meta does it, while also modifying the behavior of the relevant components pretty signficantly. (See #2856, #3188) It would be helpful to unite these different ideas into one set of extensions to leptos_meta.

I think at least #2856 and this seem to result from the fact that the pre-0.7 leptos_meta components have side effects — simply creating a <Style>, without every using it in the view that is returned, injects something into the <head>. It seems like your implementation above relies on this behavior. (i.e., mount_style does not return a view that should be rendered, but () — it is purely side effects)

I don't think I fully understand either the use case for what you're trying to do, or what you're asking for, though.