From d6c098980e0bfb6d1425591ada491774c5e9df97 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Sat, 9 Oct 2021 13:05:38 -0700 Subject: [PATCH 1/6] Add a IS_BROWSER consant to GenericNode --- packages/sycamore/src/generic_node.rs | 6 ++++++ packages/sycamore/src/generic_node/dom_node.rs | 2 ++ packages/sycamore/src/generic_node/ssr_node.rs | 2 ++ packages/sycamore/src/portal.rs | 4 ++-- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/sycamore/src/generic_node.rs b/packages/sycamore/src/generic_node.rs index 84f92c66b..488f976ab 100644 --- a/packages/sycamore/src/generic_node.rs +++ b/packages/sycamore/src/generic_node.rs @@ -42,6 +42,12 @@ pub type EventHandler = dyn Fn(Event); /// [`GenericNode`]s should be cheaply cloneable (usually backed by a [`Rc`](std::rc::Rc) or other /// reference counted container) and preserve reference equality. pub trait GenericNode: fmt::Debug + Clone + PartialEq + Eq + Hash + 'static { + /// A boolean indicating whether this node is rendered in a browser context. + /// + /// A value of `false` does not necessarily mean that it is not being rendered in WASM or even + /// in the browser. It only means that it does not create DOM nodes. + const IS_BROWSER: bool; + /// Create a new element node. fn element(tag: &str) -> Self; diff --git a/packages/sycamore/src/generic_node/dom_node.rs b/packages/sycamore/src/generic_node/dom_node.rs index 9277f7adf..b8a3f57b9 100644 --- a/packages/sycamore/src/generic_node/dom_node.rs +++ b/packages/sycamore/src/generic_node/dom_node.rs @@ -131,6 +131,8 @@ fn document() -> web_sys::Document { } impl GenericNode for DomNode { + const IS_BROWSER: bool = true; + fn element(tag: &str) -> Self { let node = document() .create_element(intern(tag)) diff --git a/packages/sycamore/src/generic_node/ssr_node.rs b/packages/sycamore/src/generic_node/ssr_node.rs index 03554eb6d..6815e2ac6 100644 --- a/packages/sycamore/src/generic_node/ssr_node.rs +++ b/packages/sycamore/src/generic_node/ssr_node.rs @@ -118,6 +118,8 @@ impl SsrNode { } impl GenericNode for SsrNode { + const IS_BROWSER: bool = false; + fn element(tag: &str) -> Self { SsrNode::new(SsrNodeType::Element(RefCell::new(Element { name: tag.to_string(), diff --git a/packages/sycamore/src/portal.rs b/packages/sycamore/src/portal.rs index 60d9fd61b..863e1d97d 100644 --- a/packages/sycamore/src/portal.rs +++ b/packages/sycamore/src/portal.rs @@ -1,6 +1,6 @@ //! Portal API. -use std::any::{Any, TypeId}; +use std::any::{Any}; use wasm_bindgen::prelude::*; @@ -20,7 +20,7 @@ where pub fn portal(props: PortalProps) -> Template { let PortalProps { children, selector } = props; - if TypeId::of::() == TypeId::of::() { + if G::IS_BROWSER { let window = web_sys::window().unwrap_throw(); let document = window.document().unwrap_throw(); let container = document From 59501ab8c8281af092c5cee031ac220c92b37da3 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Sat, 9 Oct 2021 13:16:40 -0700 Subject: [PATCH 2/6] Add `Html` trait --- packages/sycamore-macro/src/component/mod.rs | 4 ++-- packages/sycamore-macro/src/template/component.rs | 2 +- packages/sycamore/src/generic_node.rs | 6 ++++++ packages/sycamore/src/lib.rs | 1 + website/src/main.rs | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/sycamore-macro/src/component/mod.rs b/packages/sycamore-macro/src/component/mod.rs index 5a70f7980..26399a389 100644 --- a/packages/sycamore-macro/src/component/mod.rs +++ b/packages/sycamore-macro/src/component/mod.rs @@ -168,7 +168,7 @@ pub fn component_impl( let component_name_str = component_name.to_string(); let generic_node_ty = generic_node_ty.type_params().next().unwrap(); let generic_node: GenericParam = syn::parse_quote! { - #generic_node_ty: ::sycamore::generic_node::GenericNode + #generic_node_ty: ::sycamore::generic_node::Html }; let ComponentFunction { @@ -187,7 +187,7 @@ pub fn component_impl( FnArg::Typed(pat_ty) => &pat_ty.ty, }; - // Add the GenericNode type param to generics. + // Add the Html type param to generics. let first_generic_param_index = generics .params .iter() diff --git a/packages/sycamore-macro/src/template/component.rs b/packages/sycamore-macro/src/template/component.rs index ead0bf70e..25145b857 100644 --- a/packages/sycamore-macro/src/template/component.rs +++ b/packages/sycamore-macro/src/template/component.rs @@ -37,7 +37,7 @@ impl ToTokens for Component { syn::PathArguments::None => quote! {}, syn::PathArguments::AngleBracketed(mut generics) => { if !generics.args.is_empty() { - // Add the GenericNode type param to generics. + // Add the Html type param to generics. let first_generic_param_index = generics .args .iter() diff --git a/packages/sycamore/src/generic_node.rs b/packages/sycamore/src/generic_node.rs index 488f976ab..be4422cf0 100644 --- a/packages/sycamore/src/generic_node.rs +++ b/packages/sycamore/src/generic_node.rs @@ -123,3 +123,9 @@ pub trait GenericNode: fmt::Debug + Clone + PartialEq + Eq + Hash + 'static { /// Create a deep clone of the node. fn clone_node(&self) -> Self; } + +/// Trait that is implemented by all [`GenericNode`] backends that render to HTML. +pub trait Html: GenericNode {} + +impl Html for DomNode {} +impl Html for SsrNode {} diff --git a/packages/sycamore/src/lib.rs b/packages/sycamore/src/lib.rs index 51af82242..a9b8caffa 100644 --- a/packages/sycamore/src/lib.rs +++ b/packages/sycamore/src/lib.rs @@ -50,6 +50,7 @@ pub mod prelude { #[cfg(feature = "dom")] pub use crate::generic_node::DomNode; pub use crate::generic_node::GenericNode; + pub use crate::generic_node::Html; #[cfg(feature = "ssr")] pub use crate::generic_node::SsrNode; pub use crate::noderef::NodeRef; diff --git a/website/src/main.rs b/website/src/main.rs index 8d91965c3..973f92357 100644 --- a/website/src/main.rs +++ b/website/src/main.rs @@ -63,7 +63,7 @@ async fn get_sidebar(version: Option<&str>) -> SidebarData { } } -fn switch(route: StateHandle) -> Template { +fn switch(route: StateHandle) -> Template { let template = Signal::new(Template::empty()); let cached_sidebar_data: Signal, SidebarData)>> = Signal::new(None); create_effect(cloned!((template) => move || { From f9a77659183772ee465c0b8a64fadfb480b14c51 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Sat, 9 Oct 2021 13:25:42 -0700 Subject: [PATCH 3/6] Fix conditional compilation --- packages/sycamore/src/generic_node.rs | 3 --- packages/sycamore/src/generic_node/dom_node.rs | 4 +++- packages/sycamore/src/generic_node/ssr_node.rs | 4 +++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/sycamore/src/generic_node.rs b/packages/sycamore/src/generic_node.rs index be4422cf0..4171228b2 100644 --- a/packages/sycamore/src/generic_node.rs +++ b/packages/sycamore/src/generic_node.rs @@ -126,6 +126,3 @@ pub trait GenericNode: fmt::Debug + Clone + PartialEq + Eq + Hash + 'static { /// Trait that is implemented by all [`GenericNode`] backends that render to HTML. pub trait Html: GenericNode {} - -impl Html for DomNode {} -impl Html for SsrNode {} diff --git a/packages/sycamore/src/generic_node/dom_node.rs b/packages/sycamore/src/generic_node/dom_node.rs index b8a3f57b9..7b4b62f72 100644 --- a/packages/sycamore/src/generic_node/dom_node.rs +++ b/packages/sycamore/src/generic_node/dom_node.rs @@ -8,7 +8,7 @@ use wasm_bindgen::prelude::*; use wasm_bindgen::{intern, JsCast}; use web_sys::{Comment, Element, Node, Text}; -use crate::generic_node::{EventHandler, GenericNode}; +use crate::generic_node::{EventHandler, GenericNode, Html}; use crate::reactive::{create_root, on_cleanup, ReactiveScope}; use crate::template::Template; use crate::utils::render::insert; @@ -264,6 +264,8 @@ impl GenericNode for DomNode { } } +impl Html for DomNode {} + /// Render a [`Template`] into the DOM. /// Alias for [`render_to`] with `parent` being the `` tag. /// diff --git a/packages/sycamore/src/generic_node/ssr_node.rs b/packages/sycamore/src/generic_node/ssr_node.rs index 6815e2ac6..3e6934f13 100644 --- a/packages/sycamore/src/generic_node/ssr_node.rs +++ b/packages/sycamore/src/generic_node/ssr_node.rs @@ -9,7 +9,7 @@ use ahash::AHashMap; use once_cell::sync::Lazy; use wasm_bindgen::prelude::*; -use crate::generic_node::{EventHandler, GenericNode}; +use crate::generic_node::{EventHandler, GenericNode, Html}; use crate::reactive::create_root; use crate::template::Template; @@ -295,6 +295,8 @@ impl GenericNode for SsrNode { } } +impl Html for SsrNode {} + trait WriteToString { fn write_to_string(&self, s: &mut String); } From a0ad173b05166ee3e42f0fab808d58a8d102a7da Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Sat, 9 Oct 2021 13:31:49 -0700 Subject: [PATCH 4/6] Fix ui tests --- packages/sycamore-macro/tests/template/component-fail.rs | 2 +- packages/sycamore-macro/tests/template/component-pass.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sycamore-macro/tests/template/component-fail.rs b/packages/sycamore-macro/tests/template/component-fail.rs index 6ca5125bf..370eff872 100644 --- a/packages/sycamore-macro/tests/template/component-fail.rs +++ b/packages/sycamore-macro/tests/template/component-fail.rs @@ -7,7 +7,7 @@ fn c() -> Template { } } -fn compile_fail() { +fn compile_fail() { let _: Template = template! { UnknownComponent() }; let _: Template = template! { C }; diff --git a/packages/sycamore-macro/tests/template/component-pass.rs b/packages/sycamore-macro/tests/template/component-pass.rs index b565bcad1..432ee86e6 100644 --- a/packages/sycamore-macro/tests/template/component-pass.rs +++ b/packages/sycamore-macro/tests/template/component-pass.rs @@ -7,7 +7,7 @@ pub fn component() -> Template { } } -fn compile_pass() { +fn compile_pass() { let _: Template = template! { Component() }; } From 0879848140bf2fcd32885f4d0d53a956f4be0fe6 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Sat, 6 Nov 2021 11:53:53 -0700 Subject: [PATCH 5/6] Move IS_BROWSER constant to Html trait --- packages/sycamore/src/generic_node.rs | 14 +++++++------- packages/sycamore/src/generic_node/dom_node.rs | 6 +++--- packages/sycamore/src/generic_node/ssr_node.rs | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/sycamore/src/generic_node.rs b/packages/sycamore/src/generic_node.rs index 02f4186d5..ea7fd8367 100644 --- a/packages/sycamore/src/generic_node.rs +++ b/packages/sycamore/src/generic_node.rs @@ -42,12 +42,6 @@ pub type EventHandler = dyn Fn(Event); /// [`GenericNode`]s should be cheaply cloneable (usually backed by a [`Rc`](std::rc::Rc) or other /// reference counted container) and preserve reference equality. pub trait GenericNode: fmt::Debug + Clone + PartialEq + Eq + Hash + 'static { - /// A boolean indicating whether this node is rendered in a browser context. - /// - /// A value of `false` does not necessarily mean that it is not being rendered in WASM or even - /// in the browser. It only means that it does not create DOM nodes. - const IS_BROWSER: bool; - /// Create a new element node. fn element(tag: &str) -> Self; @@ -129,4 +123,10 @@ pub trait GenericNode: fmt::Debug + Clone + PartialEq + Eq + Hash + 'static { } /// Trait that is implemented by all [`GenericNode`] backends that render to HTML. -pub trait Html: GenericNode {} +pub trait Html: GenericNode { + /// A boolean indicating whether this node is rendered in a browser context. + /// + /// A value of `false` does not necessarily mean that it is not being rendered in WASM or even + /// in the browser. It only means that it does not create DOM nodes. + const IS_BROWSER: bool; +} diff --git a/packages/sycamore/src/generic_node/dom_node.rs b/packages/sycamore/src/generic_node/dom_node.rs index a7049d0c5..c72f618a3 100644 --- a/packages/sycamore/src/generic_node/dom_node.rs +++ b/packages/sycamore/src/generic_node/dom_node.rs @@ -125,8 +125,6 @@ fn document() -> web_sys::Document { } impl GenericNode for DomNode { - const IS_BROWSER: bool = true; - fn element(tag: &str) -> Self { let node = document() .create_element(intern(tag)) @@ -274,7 +272,9 @@ impl GenericNode for DomNode { } } -impl Html for DomNode {} +impl Html for DomNode { + const IS_BROWSER: bool = true; +} /// Render a [`Template`] into the DOM. /// Alias for [`render_to`] with `parent` being the `` tag. diff --git a/packages/sycamore/src/generic_node/ssr_node.rs b/packages/sycamore/src/generic_node/ssr_node.rs index fafe033f3..f984175ff 100644 --- a/packages/sycamore/src/generic_node/ssr_node.rs +++ b/packages/sycamore/src/generic_node/ssr_node.rs @@ -119,8 +119,6 @@ impl SsrNode { } impl GenericNode for SsrNode { - const IS_BROWSER: bool = false; - fn element(tag: &str) -> Self { SsrNode::new(SsrNodeType::Element(RefCell::new(Element { name: tag.to_string(), @@ -328,7 +326,9 @@ impl GenericNode for SsrNode { } } -impl Html for SsrNode {} +impl Html for SsrNode { + const IS_BROWSER: bool = false; +} trait WriteToString { fn write_to_string(&self, s: &mut String); From 2f51b18bdab093701d16b9a095600e757dc3c02a Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Sat, 6 Nov 2021 12:11:18 -0700 Subject: [PATCH 6/6] Fix doctests --- packages/sycamore/src/builder/agnostic/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/sycamore/src/builder/agnostic/mod.rs b/packages/sycamore/src/builder/agnostic/mod.rs index 0190d6fd9..8dd4a73dc 100644 --- a/packages/sycamore/src/builder/agnostic/mod.rs +++ b/packages/sycamore/src/builder/agnostic/mod.rs @@ -1,7 +1,7 @@ //! The renderer-agnostic API. use crate::component::Component; -use crate::generic_node::GenericNode; +use crate::generic_node::{GenericNode, Html}; use crate::noderef::NodeRef; use crate::template::Template; use crate::utils::render; @@ -51,13 +51,13 @@ where /// } /// /// // Elsewhere in another component. -/// # fn view() -> Template { +/// # fn view() -> Template { /// component::<_, MyComponent<_>>(()) /// # } /// ``` pub fn component(props: C::Props) -> Template where - G: GenericNode, + G: GenericNode + Html, C: Component, { C::__create_component(props) @@ -197,7 +197,7 @@ where /// h1().text("My component").build() /// } /// - /// # fn _test() -> Template { + /// # fn _test() -> Template { /// div().component::>(()).build() /// } /// ```