wip: making progress on diffing and hydration
This commit is contained in:
1 parent
e5c88fe3a4
commit
49856ccd68
34 files changed
+1023
-750
No files matched your search
+111
-58
@@ -1,3 +1,7 @@
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
@@ -12,8 +16,11 @@ use dioxus_core::*;
|
||||
|
||||
pub fn render_vnode(vnode: &VNode, string: &mut String) {}
|
||||
|
||||
pub fn render_vdom(dom: &VirtualDom) -> String {
|
||||
format!("{:}", TextRenderer::from_vdom(dom))
|
||||
pub fn render_vdom(dom: &VirtualDom, cfg: impl FnOnce(SsrConfig) -> SsrConfig) -> String {
|
||||
format!(
|
||||
"{:}",
|
||||
TextRenderer::from_vdom(dom, cfg(SsrConfig::default()))
|
||||
)
|
||||
}
|
||||
|
||||
pub fn render_vdom_scope(vdom: &VirtualDom, scope: ScopeId) -> Option<String> {
|
||||
@@ -27,29 +34,6 @@ pub fn render_vdom_scope(vdom: &VirtualDom, scope: ScopeId) -> Option<String> {
|
||||
))
|
||||
}
|
||||
|
||||
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.
|
||||
///
|
||||
///
|
||||
@@ -60,7 +44,7 @@ impl Default for SsrConfig {
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ignore
|
||||
/// const App: FC<()> = |cx| cx.render(rsx!(div { "hello world" }));
|
||||
/// static App: FC<()> = |cx| cx.render(rsx!(div { "hello world" }));
|
||||
/// let mut vdom = VirtualDom::new(App);
|
||||
/// vdom.rebuild_in_place();
|
||||
///
|
||||
@@ -81,11 +65,11 @@ impl Display for TextRenderer<'_> {
|
||||
}
|
||||
|
||||
impl<'a> TextRenderer<'a> {
|
||||
pub fn from_vdom(vdom: &'a VirtualDom) -> Self {
|
||||
pub fn from_vdom(vdom: &'a VirtualDom, cfg: SsrConfig) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
root: vdom.base_scope().root(),
|
||||
vdom: Some(vdom),
|
||||
cfg: SsrConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +116,21 @@ impl<'a> TextRenderer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// we write the element's id as a data attribute
|
||||
//
|
||||
// when the page is loaded, the `querySelectorAll` will be used to collect all the nodes, and then add
|
||||
// them interpreter's stack
|
||||
match (self.cfg.pre_render, node.element_id()) {
|
||||
(true, Some(id)) => {
|
||||
write!(f, " dio_el=\"{}\"", id)?;
|
||||
//
|
||||
for listener in el.listeners {
|
||||
// write the listeners
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.cfg.newline {
|
||||
true => write!(f, ">\n")?,
|
||||
false => write!(f, ">")?,
|
||||
@@ -162,9 +161,14 @@ impl<'a> TextRenderer<'a> {
|
||||
}
|
||||
VNodeKind::Component(vcomp) => {
|
||||
let idx = vcomp.ass_scope.get().unwrap();
|
||||
if let Some(vdom) = self.vdom {
|
||||
let new_node = vdom.get_scope(idx).unwrap().root();
|
||||
self.html_render(new_node, f, il + 1)?;
|
||||
match (self.vdom, self.cfg.skip_components) {
|
||||
(Some(vdom), false) => {
|
||||
let new_node = vdom.get_scope(idx).unwrap().root();
|
||||
self.html_render(new_node, f, il + 1)?;
|
||||
}
|
||||
_ => {
|
||||
// render the component by name
|
||||
}
|
||||
}
|
||||
}
|
||||
VNodeKind::Suspended { .. } => {
|
||||
@@ -175,6 +179,52 @@ impl<'a> TextRenderer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
// Choose to write ElementIDs into elements so the page can be re-hydrated later on
|
||||
pre_render: 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,
|
||||
pre_render: false,
|
||||
newline: false,
|
||||
skip_components: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SsrConfig {
|
||||
pub fn indent(mut self, a: bool) -> Self {
|
||||
self.indent = a;
|
||||
self
|
||||
}
|
||||
pub fn newline(mut self, a: bool) -> Self {
|
||||
self.newline = a;
|
||||
self
|
||||
}
|
||||
pub fn pre_render(mut self, a: bool) -> Self {
|
||||
self.pre_render = a;
|
||||
self
|
||||
}
|
||||
pub fn skip_components(mut self, a: bool) -> Self {
|
||||
self.skip_components = a;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -182,15 +232,14 @@ mod tests {
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_html::GlobalAttributes;
|
||||
|
||||
const SIMPLE_APP: FC<()> = |cx| {
|
||||
static SIMPLE_APP: FC<()> = |cx| {
|
||||
cx.render(rsx!(div {
|
||||
"hello world!"
|
||||
}))
|
||||
};
|
||||
|
||||
const SLIGHTLY_MORE_COMPLEX: FC<()> = |cx| {
|
||||
static SLIGHTLY_MORE_COMPLEX: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
title: "About W3Schools"
|
||||
@@ -209,14 +258,14 @@ mod tests {
|
||||
})
|
||||
};
|
||||
|
||||
const NESTED_APP: FC<()> = |cx| {
|
||||
static NESTED_APP: FC<()> = |cx| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
SIMPLE_APP {}
|
||||
}
|
||||
))
|
||||
};
|
||||
const FRAGMENT_APP: FC<()> = |cx| {
|
||||
static FRAGMENT_APP: FC<()> = |cx| {
|
||||
cx.render(rsx!(
|
||||
div { "f1" }
|
||||
div { "f2" }
|
||||
@@ -229,21 +278,28 @@ mod tests {
|
||||
fn to_string_works() {
|
||||
let mut dom = VirtualDom::new(SIMPLE_APP);
|
||||
dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
dbg!(render_vdom(&dom));
|
||||
dbg!(render_vdom(&dom, |c| c));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hydration() {
|
||||
let mut dom = VirtualDom::new(NESTED_APP);
|
||||
dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
dbg!(render_vdom(&dom, |c| c.pre_render(true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested() {
|
||||
let mut dom = VirtualDom::new(NESTED_APP);
|
||||
dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
dbg!(render_vdom(&dom));
|
||||
dbg!(render_vdom(&dom, |c| c));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fragment_app() {
|
||||
let mut dom = VirtualDom::new(FRAGMENT_APP);
|
||||
dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
dbg!(render_vdom(&dom));
|
||||
dbg!(render_vdom(&dom, |c| c));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -256,26 +312,23 @@ mod tests {
|
||||
let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX);
|
||||
dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
|
||||
file.write_fmt(format_args!("{}", TextRenderer::from_vdom(&dom)))
|
||||
.unwrap();
|
||||
file.write_fmt(format_args!(
|
||||
"{}",
|
||||
TextRenderer::from_vdom(&dom, SsrConfig::default())
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn styles() {
|
||||
// const STLYE_APP: FC<()> = |cx| {
|
||||
// //
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// style: {
|
||||
// color: "blue",
|
||||
// font_size: "46px"
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// };
|
||||
#[test]
|
||||
fn styles() {
|
||||
static STLYE_APP: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div { style: { color: "blue", font_size: "46px" } }
|
||||
})
|
||||
};
|
||||
|
||||
// let mut dom = VirtualDom::new(STLYE_APP);
|
||||
// dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
// dbg!(render_vdom(&dom));
|
||||
// }
|
||||
let mut dom = VirtualDom::new(STLYE_APP);
|
||||
dom.rebuild_in_place().expect("failed to run virtualdom");
|
||||
dbg!(render_vdom(&dom, |c| c));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user