Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot return <template /> from a component #64

Closed
jquesada2016 opened this issue Nov 8, 2022 · 3 comments
Closed

Cannot return <template /> from a component #64

jquesada2016 opened this issue Nov 8, 2022 · 3 comments

Comments

@jquesada2016
Copy link
Contributor

The following example results in a panic:

use leptos::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn start() {
  console_error_panic_hook::set_once();

  mount_to_body(view_fn);
}

fn view_fn(cx: Scope) -> impl Mountable {
  view! { cx,
    <TemplateComponent></TemplateComponent>
  }
}

#[component]
fn TemplateComponent(cx: Scope) -> Element {
  view! { cx,
    <template>
      <div>"Just doing the Lord's work."</div>
    </template>
  }
}

This only seems to happen if directly returning a <template /> from the top level of a component.

The full stack trace is:

Uncaught (in promise) Error: `unwrap_throw` failed
    at imports.wbg.__wbindgen_throw (wasm.js?t=1667929395579:292:15)
    at wasm_bindgen::throw_str::hafba1a1a4c068143 (wasm_bg.wasm:0x4508d)
    at <core::option::Option<T> as wasm_bindgen::UnwrapThrowExt<T>>::expect_throw::h01d589852a07341a (wasm_bg.wasm:0x3ac67)
    at wasm_bindgen::UnwrapThrowExt::unwrap_throw::h568eba629f01842e (wasm_bg.wasm:0x42212)
    at wasm::TemplateComponent::hb3dcae73f423c169 (wasm_bg.wasm:0x3149c)
    at wasm::view_fn::{{closure}}::h573caef1eccbc7ff (wasm_bg.wasm:0x3f78f)
    at leptos_reactive::scope::Scope::untrack::hf1b86e9da7ad8dd0 (wasm_bg.wasm:0x320d5)
    at leptos_dom::create_component::ha566be4d30a0487a (wasm_bg.wasm:0x3fae6)
    at wasm::view_fn::he21f89cb96e65078 (wasm_bg.wasm:0x392b3)
    at core::ops::function::Fn::call::ha4ca8e44e588d793

Also, reading the stack trace, just a heads up, using unwrap_throw is unsound as it leads the stack in a potentially non-reentrant state, so if a user catches the JS exception, they will most likely experience UB.

@gbj
Copy link
Collaborator

gbj commented Nov 8, 2022

"Just doing the Lord's work" 🤣

Leptos already constructs a <template> for every view macro and then clones when you need the actual DOM nodes. So what your TemplateComponent is doing is basically:

let template = document.create_element("template");
template.set_inner_html("<template>Just doing the Lord's work.</template>");
let root = template.clone_node_with_deep(true);
let el1 = root.first_child().unwrap_throw(); // panics here

It panics because it's trying to iterate over the child nodes and a template element doesn't have child nodes; they live in a document fragment in its .content field.

I guess the view macro could detect the special case of a <template> and act accordingly, but... I'm not sure you ever need to explicitly use a <template> while using Leptos anyway. I'd be curious to hear the use case, if you are!

@jquesada2016
Copy link
Contributor Author

Sure! The reason I am using a <template /> is to interface with the tippy.js JavaScript library in order to create a menu. It's not needed, I just switched to using a <div />, which works just as well. It's just more semantically correct to use a <template />, as that's exactly what it is.

@gbj
Copy link
Collaborator

gbj commented Nov 13, 2022

This should now be possible in d4da7e0. The example I used to test it is is pretty cool and shows exactly what a thin layer over the DOM Leptos is providing. You can basically take an HtmlTemplateElement returned by view!(), clone its contents, and take the DocumentFragment that gives you and stick it straight into another view!() macro as a child. Super fun.

@gbj gbj closed this as completed Nov 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants