mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 14:44:12 +00:00
fix hydration
This commit is contained in:
parent
d20422bb0f
commit
694bef0d93
8 changed files with 76 additions and 21 deletions
|
@ -111,7 +111,7 @@ impl Config {
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
{
|
{
|
||||||
let cfg = self.web_cfg.hydrate(true);
|
let cfg = self.web_cfg.hydrate(true);
|
||||||
dioxus_web::run(
|
dioxus_web::launch::launch_virtual_dom(
|
||||||
// TODO: this should pull the props from the document
|
// TODO: this should pull the props from the document
|
||||||
build_virtual_dom(),
|
build_virtual_dom(),
|
||||||
cfg,
|
cfg,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! This module contains the `launch` function, which is the main entry point for dioxus fullstack
|
//! This module contains the `launch` function, which is the main entry point for dioxus fullstack
|
||||||
|
|
||||||
|
use core::panic;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use dioxus_lib::prelude::{Element, VirtualDom};
|
use dioxus_lib::prelude::{Element, VirtualDom};
|
||||||
|
|
|
@ -87,7 +87,6 @@ mod js {
|
||||||
templates[tmpl_id] = nodes;
|
templates[tmpl_id] = nodes;
|
||||||
}
|
}
|
||||||
export function hydrate(ids) {
|
export function hydrate(ids) {
|
||||||
console.log("hydrating", ids);
|
|
||||||
const hydrateNodes = document.querySelectorAll('[data-node-hydration]');
|
const hydrateNodes = document.querySelectorAll('[data-node-hydration]');
|
||||||
for (let i = 0; i < hydrateNodes.length; i++) {
|
for (let i = 0; i < hydrateNodes.length; i++) {
|
||||||
const hydrateNode = hydrateNodes[i];
|
const hydrateNode = hydrateNodes[i];
|
||||||
|
@ -95,7 +94,6 @@ mod js {
|
||||||
const split = hydration.split(',');
|
const split = hydration.split(',');
|
||||||
const id = ids[parseInt(split[0])];
|
const id = ids[parseInt(split[0])];
|
||||||
nodes[id] = hydrateNode;
|
nodes[id] = hydrateNode;
|
||||||
console.log("hydrating node", hydrateNode, id);
|
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
hydrateNode.listening = split.length - 1;
|
hydrateNode.listening = split.length - 1;
|
||||||
hydrateNode.setAttribute('data-dioxus-id', id);
|
hydrateNode.setAttribute('data-dioxus-id', id);
|
||||||
|
@ -104,7 +102,6 @@ mod js {
|
||||||
const split2 = listener.split(':');
|
const split2 = listener.split(':');
|
||||||
const event_name = split2[0];
|
const event_name = split2[0];
|
||||||
const bubbles = split2[1] === '1';
|
const bubbles = split2[1] === '1';
|
||||||
console.log("hydrating listener", event_name, bubbles);
|
|
||||||
listeners.create(event_name, hydrateNode, bubbles);
|
listeners.create(event_name, hydrateNode, bubbles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +115,6 @@ mod js {
|
||||||
const id = currentNode.textContent;
|
const id = currentNode.textContent;
|
||||||
const split = id.split('node-id');
|
const split = id.split('node-id');
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
console.log("hydrating text", currentNode.nextSibling, id);
|
|
||||||
nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
|
nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
|
||||||
}
|
}
|
||||||
currentNode = treeWalker.nextNode();
|
currentNode = treeWalker.nextNode();
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
/// dioxus_web::launch(App, Config::new().hydrate(true).root_name("myroot"))
|
/// dioxus_web::launch(App, Config::new().hydrate(true).root_name("myroot"))
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[cfg(feature = "hydrate")]
|
|
||||||
pub(crate) hydrate: bool,
|
pub(crate) hydrate: bool,
|
||||||
pub(crate) rootname: String,
|
pub(crate) rootname: String,
|
||||||
pub(crate) default_panic_hook: bool,
|
pub(crate) default_panic_hook: bool,
|
||||||
|
@ -17,7 +16,6 @@ pub struct Config {
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(feature = "hydrate")]
|
|
||||||
hydrate: false,
|
hydrate: false,
|
||||||
rootname: "main".to_string(),
|
rootname: "main".to_string(),
|
||||||
default_panic_hook: true,
|
default_panic_hook: true,
|
||||||
|
|
|
@ -12,11 +12,18 @@ pub fn launch(
|
||||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any>>>,
|
contexts: Vec<Box<dyn Fn() -> Box<dyn Any>>>,
|
||||||
platform_config: Config,
|
platform_config: Config,
|
||||||
) {
|
) {
|
||||||
|
let mut vdom = VirtualDom::new(root);
|
||||||
|
for context in contexts {
|
||||||
|
vdom.insert_any_root_context(context());
|
||||||
|
}
|
||||||
|
launch_virtual_dom(vdom, platform_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch the web application with a prebuild virtual dom
|
||||||
|
///
|
||||||
|
/// For a builder API, see `LaunchBuilder` defined in the `dioxus` crate.
|
||||||
|
pub fn launch_virtual_dom(vdom: VirtualDom, platform_config: Config) {
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
let mut vdom = VirtualDom::new(root);
|
|
||||||
for context in contexts {
|
|
||||||
vdom.insert_any_root_context(context());
|
|
||||||
}
|
|
||||||
crate::run(vdom, platform_config).await;
|
crate::run(vdom, platform_config).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,10 +121,7 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) {
|
||||||
|
|
||||||
let (tx, mut rx) = futures_channel::mpsc::unbounded();
|
let (tx, mut rx) = futures_channel::mpsc::unbounded();
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
|
||||||
let should_hydrate = web_config.hydrate;
|
let should_hydrate = web_config.hydrate;
|
||||||
#[cfg(not(feature = "hydrate"))]
|
|
||||||
let should_hydrate = false;
|
|
||||||
|
|
||||||
let mut websys_dom = dom::WebsysDom::new(web_config, tx);
|
let mut websys_dom = dom::WebsysDom::new(web_config, tx);
|
||||||
|
|
||||||
|
@ -133,13 +130,8 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) {
|
||||||
if should_hydrate {
|
if should_hydrate {
|
||||||
#[cfg(feature = "hydrate")]
|
#[cfg(feature = "hydrate")]
|
||||||
{
|
{
|
||||||
// todo: we need to split rebuild and initialize into two phases
|
dom.rebuild(&mut crate::rehydrate::OnlyWriteTemplates(&mut websys_dom));
|
||||||
// it's a waste to produce edits just to get the vdom loaded
|
|
||||||
|
|
||||||
{
|
|
||||||
dom.rebuild(&mut websys_dom);
|
|
||||||
websys_dom.flush_edits();
|
|
||||||
}
|
|
||||||
if let Err(err) = websys_dom.rehydrate(&dom) {
|
if let Err(err) = websys_dom.rehydrate(&dom) {
|
||||||
tracing::error!("Rehydration failed. {:?}", err);
|
tracing::error!("Rehydration failed. {:?}", err);
|
||||||
tracing::error!("Rebuild DOM into element from scratch");
|
tracing::error!("Rebuild DOM into element from scratch");
|
||||||
|
|
|
@ -12,7 +12,7 @@ use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
impl WebsysDom {
|
impl WebsysDom {
|
||||||
fn create_template_node(&self, v: &TemplateNode) -> web_sys::Node {
|
pub(crate) fn create_template_node(&self, v: &TemplateNode) -> web_sys::Node {
|
||||||
use TemplateNode::*;
|
use TemplateNode::*;
|
||||||
match v {
|
match v {
|
||||||
Element {
|
Element {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::dom::WebsysDom;
|
use crate::dom::WebsysDom;
|
||||||
|
use dioxus_core::prelude::*;
|
||||||
use dioxus_core::AttributeValue;
|
use dioxus_core::AttributeValue;
|
||||||
|
use dioxus_core::WriteMutations;
|
||||||
use dioxus_core::{DynamicNode, ElementId, ScopeState, TemplateNode, VNode, VirtualDom};
|
use dioxus_core::{DynamicNode, ElementId, ScopeState, TemplateNode, VNode, VirtualDom};
|
||||||
|
use dioxus_interpreter_js::save_template;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RehydrationError {
|
pub enum RehydrationError {
|
||||||
|
@ -149,3 +152,61 @@ impl WebsysDom {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// During rehydration, we don't want to actually write anything to the DOM, but we do need to store any templates that were created. This struct is used to only write templates to the DOM.
|
||||||
|
pub(crate) struct OnlyWriteTemplates<'a>(pub &'a mut WebsysDom);
|
||||||
|
|
||||||
|
impl WriteMutations for OnlyWriteTemplates<'_> {
|
||||||
|
fn register_template(&mut self, template: Template) {
|
||||||
|
let mut roots = vec![];
|
||||||
|
|
||||||
|
for root in template.roots {
|
||||||
|
roots.push(self.0.create_template_node(root))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.templates
|
||||||
|
.insert(template.name.to_owned(), self.0.max_template_id);
|
||||||
|
save_template(roots, self.0.max_template_id);
|
||||||
|
self.0.max_template_id += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_children(&mut self, _: ElementId, _: usize) {}
|
||||||
|
|
||||||
|
fn assign_node_id(&mut self, _: &'static [u8], _: ElementId) {}
|
||||||
|
|
||||||
|
fn create_placeholder(&mut self, _: ElementId) {}
|
||||||
|
|
||||||
|
fn create_text_node(&mut self, _: &str, _: ElementId) {}
|
||||||
|
|
||||||
|
fn hydrate_text_node(&mut self, _: &'static [u8], _: &str, _: ElementId) {}
|
||||||
|
|
||||||
|
fn load_template(&mut self, _: &'static str, _: usize, _: ElementId) {}
|
||||||
|
|
||||||
|
fn replace_node_with(&mut self, _: ElementId, _: usize) {}
|
||||||
|
|
||||||
|
fn replace_placeholder_with_nodes(&mut self, _: &'static [u8], _: usize) {}
|
||||||
|
|
||||||
|
fn insert_nodes_after(&mut self, _: ElementId, _: usize) {}
|
||||||
|
|
||||||
|
fn insert_nodes_before(&mut self, _: ElementId, _: usize) {}
|
||||||
|
|
||||||
|
fn set_attribute(
|
||||||
|
&mut self,
|
||||||
|
_: &'static str,
|
||||||
|
_: Option<&'static str>,
|
||||||
|
_: &AttributeValue,
|
||||||
|
_: ElementId,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_node_text(&mut self, _: &str, _: ElementId) {}
|
||||||
|
|
||||||
|
fn create_event_listener(&mut self, _: &'static str, _: ElementId) {}
|
||||||
|
|
||||||
|
fn remove_event_listener(&mut self, _: &'static str, _: ElementId) {}
|
||||||
|
|
||||||
|
fn remove_node(&mut self, _: ElementId) {}
|
||||||
|
|
||||||
|
fn push_root(&mut self, _: ElementId) {}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue