diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 63add18b6..856e32e85 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -531,7 +531,7 @@ pub mod on { /// The key isn't an enum because there are just so many context-dependent keys. /// /// A full list on which keys to use is available at: - /// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + /// /// /// # Example /// diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index af0775f6c..385268ec8 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -180,25 +180,7 @@ impl VirtualDom { /// SSR takes advantage of this by using Dioxus itself as the source of truth, and rendering from the tree directly. pub fn rebuild_in_place(&mut self) -> Result<()> { let mut realdom = DebugDom::new(); - let mut diff_machine = DiffMachine::new( - &mut realdom, - &self.components, - self.base_scope, - self.event_queue.clone(), - &self.tasks, - ); - - // Schedule an update and then immediately call it on the root component - // This is akin to a hook being called from a listener and requring a re-render - // Instead, this is done on top-level component - let base = self.components.try_get(self.base_scope)?; - - let update = &base.event_channel; - update(); - - self.progress_completely(&mut diff_machine)?; - - Ok(()) + self.rebuild(&mut realdom) } /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch diff --git a/packages/ssr/index.html b/packages/ssr/index.html index fe9879cff..f30e4dac9 100644 --- a/packages/ssr/index.html +++ b/packages/ssr/index.html @@ -1,3 +1,62 @@ -
-hello world! +
+
+

Hello world!: 0

+
+
+

Hello world!: 1

+
+
+

Hello world!: 2

+
+
+

Hello world!: 3

+
+
+

Hello world!: 4

+
+
+

Hello world!: 5

+
+
+

Hello world!: 6

+
+
+

Hello world!: 7

+
+
+

Hello world!: 8

+
+
+

Hello world!: 9

+
+
+

Hello world!: 10

+
+
+

Hello world!: 11

+
+
+

Hello world!: 12

+
+
+

Hello world!: 13

+
+
+

Hello world!: 14

+
+
+

Hello world!: 15

+
+
+

Hello world!: 16

+
+
+

Hello world!: 17

+
+
+

Hello world!: 18

+
+
+

Hello world!: 19

+
diff --git a/packages/ssr/src/lib.rs b/packages/ssr/src/lib.rs index 8ada48b7a..38fb8d6b2 100644 --- a/packages/ssr/src/lib.rs +++ b/packages/ssr/src/lib.rs @@ -1,5 +1,3 @@ -//! Dioxus Server-Side-Rendering -//! //! This crate demonstrates how to implement a custom renderer for Dioxus VNodes via the `TextRenderer` renderer. //! The `TextRenderer` consumes a Dioxus Virtual DOM, progresses its event queue, and renders the VNodes to a String. //! @@ -18,6 +16,29 @@ pub fn render_root(vdom: &VirtualDom) -> String { format!("{:}", TextRenderer::new(vdom)) } +pub struct SsrConfig { + // currently not supported - control if we indent the HTML output + indent: bool, + + // Control if elements are written onto a new line + newline: bool, + + // Currently not implemented + // Don't proceed onto new components. Instead, put the name of the component. + // TODO: components don't have names :( + skip_components: bool, +} + +impl Default for SsrConfig { + fn default() -> Self { + Self { + indent: false, + + newline: false, + skip_components: false, + } + } +} /// A configurable text renderer for the Dioxus VirtualDOM. /// /// @@ -26,48 +47,71 @@ pub fn render_root(vdom: &VirtualDom) -> String { /// This uses the `Formatter` infrastructure so you can write into anything that supports `write_fmt`. We can't accept /// any generic writer, so you need to "Display" the text renderer. This is done through `format!` or `format_args!` /// +/// ## Example +/// ```ignore +/// const App: FC<()> = |cx| cx.render(rsx!(div { "hello world" })); +/// let mut vdom = VirtualDom::new(App); +/// vdom.rebuild_in_place(); /// -/// -/// +/// let renderer = TextRenderer::new(&vdom); +/// let output = format!("{}", renderer); +/// assert_eq!(output, "
hello world
"); +/// ``` pub struct TextRenderer<'a> { vdom: &'a VirtualDom, + cfg: SsrConfig, } impl<'a> TextRenderer<'a> { fn new(vdom: &'a VirtualDom) -> Self { - Self { vdom } + Self { + vdom, + cfg: SsrConfig::default(), + } } fn html_render(&self, node: &VNode, f: &mut std::fmt::Formatter) -> std::fmt::Result { match node { + VNode::Text(text) => write!(f, "{}", text.text)?, VNode::Element(el) => { write!(f, "<{}", el.tag_name)?; for attr in el.attributes { write!(f, " {}=\"{}\"", attr.name, attr.value)?; } - write!(f, ">\n")?; + match self.cfg.newline { + true => write!(f, ">\n")?, + false => write!(f, ">")?, + } + for child in el.children { self.html_render(child, f)?; } - write!(f, "\n", el.tag_name)?; - Ok(()) + match self.cfg.newline { + true => write!(f, "\n", el.tag_name)?, + false => write!(f, "", el.tag_name)?, + } + } + VNode::Fragment(frag) => { + for child in frag.children { + self.html_render(child, f)?; + } } - VNode::Text(text) => write!(f, "{}", text.text), - VNode::Suspended { .. } => todo!(), VNode::Component(vcomp) => { - todo!() - // let id = vcomp.ass_scope.borrow().unwrap(); - // let id = vcomp.ass_scope.as_ref().borrow().unwrap(); - // let new_node = dom - // .components - // .try_get(id) - // .unwrap() - // .frames - // .current_head_node(); - // html_render(&dom, new_node, f) + let idx = vcomp.ass_scope.get().unwrap(); + + let new_node = self + .vdom + .components + .try_get(idx) + .unwrap() + .frames + .current_head_node(); + + self.html_render(new_node, f)?; } - VNode::Fragment(_) => todo!(), + VNode::Suspended { .. } => todo!(), } + Ok(()) } } @@ -125,7 +169,7 @@ mod tests { let mut file = File::create("index.html").unwrap(); - let mut dom = VirtualDom::new(SIMPLE_APP); + let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX); dom.rebuild_in_place().expect("failed to run virtualdom"); file.write_fmt(format_args!("{}", TextRenderer::new(&dom)))