wip: stop transmuting reference
This commit is contained in:
1 parent
d407035931
commit
491bf4332d
8 files changed
+263
-244
No files matched your search
+1
-6
@@ -2,12 +2,7 @@ use dioxus::prelude::*;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dioxus_desktop::launch(|cx| {
|
dioxus_desktop::launch(|cx| render!(app_root {}));
|
||||||
cx.render(rsx! {
|
|
||||||
h1 {"Loading...."}
|
|
||||||
app_root {}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Deserialize)]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use crate::factory::RenderReturn;
|
use crate::factory::RenderReturn;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
pub struct BumpFrame {
|
pub struct BumpFrame {
|
||||||
pub bump: Bump,
|
pub bump: Bump,
|
||||||
|
|||||||
+203
-117
@@ -1,22 +1,36 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
use crate::factory::RenderReturn;
|
use crate::factory::RenderReturn;
|
||||||
use crate::innerlude::{Mutations, SuspenseContext, VText};
|
use crate::innerlude::{Mutations, VComponent, VFragment, VText};
|
||||||
use crate::mutations::Mutation;
|
use crate::mutations::Mutation;
|
||||||
use crate::mutations::Mutation::*;
|
use crate::mutations::Mutation::*;
|
||||||
use crate::nodes::VNode;
|
use crate::nodes::VNode;
|
||||||
use crate::nodes::{DynamicNode, TemplateNode};
|
use crate::nodes::{DynamicNode, TemplateNode};
|
||||||
use crate::virtual_dom::VirtualDom;
|
use crate::virtual_dom::VirtualDom;
|
||||||
use crate::{AttributeValue, ScopeId, TemplateAttribute};
|
use crate::{AttributeValue, ElementId, ScopeId, SuspenseContext, TemplateAttribute};
|
||||||
|
|
||||||
impl VirtualDom {
|
impl VirtualDom {
|
||||||
|
/// Create a new template [`VNode`] and write it to the [`Mutations`] buffer.
|
||||||
|
///
|
||||||
|
/// This method pushes the ScopeID to the internal scopestack and returns the number of nodes created.
|
||||||
pub(crate) fn create_scope<'a>(
|
pub(crate) fn create_scope<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: ScopeId,
|
scope: ScopeId,
|
||||||
mutations: &mut Mutations<'a>,
|
mutations: &mut Mutations<'a>,
|
||||||
template: &'a VNode<'a>,
|
template: &'a VNode<'a>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
|
let mutations_to_this_point = mutations.len();
|
||||||
|
|
||||||
self.scope_stack.push(scope);
|
self.scope_stack.push(scope);
|
||||||
let out = self.create(mutations, template);
|
let out = self.create(mutations, template);
|
||||||
self.scope_stack.pop();
|
self.scope_stack.pop();
|
||||||
|
|
||||||
|
if !self.collected_leaves.is_empty() {
|
||||||
|
if let Some(boundary) = self.scopes[scope.0].has_context::<SuspenseContext>() {
|
||||||
|
println!("Boundary detected and pending leaves!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,18 +43,7 @@ impl VirtualDom {
|
|||||||
// The best renderers will have templates prehydrated and registered
|
// The best renderers will have templates prehydrated and registered
|
||||||
// Just in case, let's create the template using instructions anyways
|
// Just in case, let's create the template using instructions anyways
|
||||||
if !self.templates.contains_key(&template.template.id) {
|
if !self.templates.contains_key(&template.template.id) {
|
||||||
for node in template.template.roots {
|
self.register_template(template, mutations);
|
||||||
let mutations = &mut mutations.template_mutations;
|
|
||||||
self.create_static_node(mutations, template, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutations.template_mutations.push(SaveTemplate {
|
|
||||||
name: template.template.id,
|
|
||||||
m: template.template.roots.len(),
|
|
||||||
});
|
|
||||||
|
|
||||||
self.templates
|
|
||||||
.insert(template.template.id, template.template.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the roots, creating nodes and assigning IDs
|
// Walk the roots, creating nodes and assigning IDs
|
||||||
@@ -167,6 +170,21 @@ impl VirtualDom {
|
|||||||
on_stack
|
on_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a new template into the VirtualDom's template registry
|
||||||
|
fn register_template<'a>(&mut self, template: &'a VNode<'a>, mutations: &mut Mutations<'a>) {
|
||||||
|
for node in template.template.roots {
|
||||||
|
self.create_static_node(&mut mutations.template_mutations, template, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutations.template_mutations.push(SaveTemplate {
|
||||||
|
name: template.template.id,
|
||||||
|
m: template.template.roots.len(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.templates
|
||||||
|
.insert(template.template.id, template.template);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn create_static_node<'a>(
|
pub(crate) fn create_static_node<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mutations: &mut Vec<Mutation<'a>>,
|
mutations: &mut Vec<Mutation<'a>>,
|
||||||
@@ -234,125 +252,193 @@ impl VirtualDom {
|
|||||||
node: &'a DynamicNode<'a>,
|
node: &'a DynamicNode<'a>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
match &node {
|
use DynamicNode::*;
|
||||||
DynamicNode::Text(VText { id, value }) => {
|
match node {
|
||||||
let new_id = self.next_element(template, template.template.node_paths[idx]);
|
Text(text) => self.create_dynamic_text(mutations, template, text, idx),
|
||||||
id.set(new_id);
|
Placeholder(slot) => self.create_placeholder(template, idx, slot, mutations),
|
||||||
mutations.push(HydrateText {
|
Fragment(frag) => self.create_fragment(frag, mutations),
|
||||||
id: new_id,
|
Component(component) => self.create_component_node(mutations, template, component, idx),
|
||||||
path: &template.template.node_paths[idx][1..],
|
}
|
||||||
value,
|
}
|
||||||
});
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicNode::Component(component) => {
|
fn create_dynamic_text<'a>(
|
||||||
let props = component.props.replace(None).unwrap();
|
&mut self,
|
||||||
let prop_ptr = unsafe { std::mem::transmute(props.as_ref()) };
|
mutations: &mut Mutations<'a>,
|
||||||
let scope = self.new_scope(prop_ptr).id;
|
template: &VNode<'a>,
|
||||||
component.props.replace(Some(props));
|
text: &VText<'a>,
|
||||||
|
idx: usize,
|
||||||
|
) -> usize {
|
||||||
|
// Allocate a dynamic element reference for this text node
|
||||||
|
let new_id = self.next_element(template, template.template.node_paths[idx]);
|
||||||
|
|
||||||
component.scope.set(Some(scope));
|
// Make sure the text node is assigned to the correct element
|
||||||
|
text.id.set(new_id);
|
||||||
|
|
||||||
let return_nodes = unsafe { self.run_scope(scope).extend_lifetime_ref() };
|
// Add the mutation to the list
|
||||||
|
mutations.push(HydrateText {
|
||||||
|
id: new_id,
|
||||||
|
path: &template.template.node_paths[idx][1..],
|
||||||
|
value: text.value,
|
||||||
|
});
|
||||||
|
|
||||||
match return_nodes {
|
// Since we're hydrating an existing node, we don't create any new nodes
|
||||||
RenderReturn::Sync(None) => {
|
0
|
||||||
todo!()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RenderReturn::Async(_) => {
|
fn create_placeholder(
|
||||||
let new_id = self.next_element(template, template.template.node_paths[idx]);
|
&mut self,
|
||||||
component.placeholder.set(Some(new_id));
|
template: &VNode,
|
||||||
self.scopes[scope.0].placeholder.set(Some(new_id));
|
idx: usize,
|
||||||
|
slot: &Cell<ElementId>,
|
||||||
|
mutations: &mut Mutations,
|
||||||
|
) -> usize {
|
||||||
|
// Allocate a dynamic element reference for this text node
|
||||||
|
let id = self.next_element(template, template.template.node_paths[idx]);
|
||||||
|
|
||||||
mutations.push(AssignId {
|
// Make sure the text node is assigned to the correct element
|
||||||
id: new_id,
|
slot.set(id);
|
||||||
path: &template.template.node_paths[idx][1..],
|
|
||||||
});
|
|
||||||
|
|
||||||
let boudary = self.scopes[scope.0]
|
// Assign the ID to the existing node in the template
|
||||||
.consume_context::<SuspenseContext>()
|
mutations.push(AssignId {
|
||||||
.unwrap();
|
path: &template.template.node_paths[idx][1..],
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
if boudary.placeholder.get().is_none() {
|
// Since the placeholder is already in the DOM, we don't create any new nodes
|
||||||
boudary.placeholder.set(Some(new_id));
|
0
|
||||||
}
|
}
|
||||||
boudary
|
|
||||||
.waiting_on
|
|
||||||
.borrow_mut()
|
|
||||||
.extend(self.collected_leaves.drain(..));
|
|
||||||
|
|
||||||
0
|
fn create_fragment<'a>(
|
||||||
}
|
&mut self,
|
||||||
|
frag: &'a VFragment<'a>,
|
||||||
|
mutations: &mut Mutations<'a>,
|
||||||
|
) -> usize {
|
||||||
|
frag.nodes
|
||||||
|
.iter()
|
||||||
|
.fold(0, |acc, child| acc + self.create(mutations, child))
|
||||||
|
}
|
||||||
|
|
||||||
RenderReturn::Sync(Some(template)) => {
|
fn create_component_node<'a>(
|
||||||
let mutations_to_this_point = mutations.len();
|
&mut self,
|
||||||
|
mutations: &mut Mutations<'a>,
|
||||||
|
template: &'a VNode<'a>,
|
||||||
|
component: &'a VComponent<'a>,
|
||||||
|
idx: usize,
|
||||||
|
) -> usize {
|
||||||
|
let props = component.props.replace(None).unwrap();
|
||||||
|
|
||||||
self.scope_stack.push(scope);
|
let prop_ptr = unsafe { std::mem::transmute(props.as_ref()) };
|
||||||
let mut created = self.create(mutations, template);
|
let scope = self.new_scope(prop_ptr).id;
|
||||||
self.scope_stack.pop();
|
|
||||||
|
|
||||||
if !self.collected_leaves.is_empty() {
|
component.props.replace(Some(props));
|
||||||
if let Some(boundary) =
|
component.scope.set(Some(scope));
|
||||||
self.scopes[scope.0].has_context::<SuspenseContext>()
|
|
||||||
{
|
|
||||||
// Since this is a boundary, use it as a placeholder
|
|
||||||
let new_id =
|
|
||||||
self.next_element(template, template.template.node_paths[idx]);
|
|
||||||
component.placeholder.set(Some(new_id));
|
|
||||||
self.scopes[scope.0].placeholder.set(Some(new_id));
|
|
||||||
mutations.push(AssignId {
|
|
||||||
id: new_id,
|
|
||||||
path: &template.template.node_paths[idx][1..],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Now connect everything to the boundary
|
let return_nodes = unsafe { self.run_scope(scope).extend_lifetime_ref() };
|
||||||
let boundary_mut = boundary;
|
|
||||||
let split_off = mutations.split_off(mutations_to_this_point);
|
|
||||||
let split_off: Vec<Mutation> =
|
|
||||||
unsafe { std::mem::transmute(split_off) };
|
|
||||||
|
|
||||||
if boundary_mut.placeholder.get().is_none() {
|
use RenderReturn::*;
|
||||||
boundary_mut.placeholder.set(Some(new_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the generated edits, we want to pick off from where we left off.
|
match return_nodes {
|
||||||
boundary_mut.mutations.borrow_mut().edits.extend(split_off);
|
Sync(Some(t)) => self.create_component(mutations, scope, t, idx, component),
|
||||||
|
Sync(None) | Async(_) => {
|
||||||
boundary_mut
|
self.create_component_placeholder(template, idx, component, scope, mutations)
|
||||||
.waiting_on
|
|
||||||
.borrow_mut()
|
|
||||||
.extend(self.collected_leaves.drain(..));
|
|
||||||
|
|
||||||
created = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle any waiting on futures accumulated by async calls down the tree
|
|
||||||
// if this is a boundary, we split off the tree
|
|
||||||
created
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicNode::Fragment(frag) => {
|
|
||||||
// Todo: if there's no children create a placeholder instead ?
|
|
||||||
frag.nodes
|
|
||||||
.iter()
|
|
||||||
.fold(0, |acc, child| acc + self.create(mutations, child))
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicNode::Placeholder(slot) => {
|
|
||||||
let id = self.next_element(template, template.template.node_paths[idx]);
|
|
||||||
slot.set(id);
|
|
||||||
mutations.push(AssignId {
|
|
||||||
path: &template.template.node_paths[idx][1..],
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_component<'a>(
|
||||||
|
&mut self,
|
||||||
|
mutations: &mut Mutations<'a>,
|
||||||
|
scope: ScopeId,
|
||||||
|
template: &'a VNode<'a>,
|
||||||
|
idx: usize,
|
||||||
|
component: &'a VComponent<'a>,
|
||||||
|
) -> usize {
|
||||||
|
// // Keep track of how many mutations are in the buffer in case we need to split them out if a suspense boundary
|
||||||
|
// // is encountered
|
||||||
|
// let mutations_to_this_point = mutations.len();
|
||||||
|
|
||||||
|
// Create the component's root element
|
||||||
|
let created = self.create_scope(scope, mutations, template);
|
||||||
|
|
||||||
|
if !self.collected_leaves.is_empty() {
|
||||||
|
println!("collected leaves: {:?}", self.collected_leaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
created
|
||||||
|
|
||||||
|
// // If running the scope has collected some leaves and *this* component is a boundary, then handle the suspense
|
||||||
|
// let boundary = match self.scopes[scope.0].has_context::<SuspenseContext>() {
|
||||||
|
// Some(boundary) if !self.collected_leaves.is_empty() => boundary,
|
||||||
|
// _ => return created,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Since this is a boundary, use it as a placeholder
|
||||||
|
// let new_id = self.next_element(template, template.template.node_paths[idx]);
|
||||||
|
// component.placeholder.set(Some(new_id));
|
||||||
|
// self.scopes[scope.0].placeholder.set(Some(new_id));
|
||||||
|
// mutations.push(AssignId {
|
||||||
|
// id: new_id,
|
||||||
|
// path: &template.template.node_paths[idx][1..],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Now connect everything to the boundary
|
||||||
|
// let boundary_mut = boundary;
|
||||||
|
// let split_off = mutations.split_off(mutations_to_this_point);
|
||||||
|
// let split_off: Vec<Mutation> = unsafe { std::mem::transmute(split_off) };
|
||||||
|
|
||||||
|
// if boundary_mut.placeholder.get().is_none() {
|
||||||
|
// boundary_mut.placeholder.set(Some(new_id));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // In the generated edits, we want to pick off from where we left off.
|
||||||
|
// boundary_mut.mutations.borrow_mut().edits.extend(split_off);
|
||||||
|
|
||||||
|
// boundary_mut
|
||||||
|
// .waiting_on
|
||||||
|
// .borrow_mut()
|
||||||
|
// .extend(self.collected_leaves.drain(..));
|
||||||
|
|
||||||
|
// 0
|
||||||
|
|
||||||
|
// let boudary = self.scopes[scope.0]
|
||||||
|
// .consume_context::<SuspenseContext>()
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
// boudary
|
||||||
|
// .waiting_on
|
||||||
|
// .borrow_mut()
|
||||||
|
// .extend(self.collected_leaves.drain(..));
|
||||||
|
|
||||||
|
// if boudary.placeholder.get().is_none() {
|
||||||
|
// boudary.placeholder.set(Some(new_id));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take the rendered nodes from a component and handle them if they were async
|
||||||
|
///
|
||||||
|
/// IE simply assign an ID to the placeholder
|
||||||
|
fn create_component_placeholder(
|
||||||
|
&mut self,
|
||||||
|
template: &VNode,
|
||||||
|
idx: usize,
|
||||||
|
component: &VComponent,
|
||||||
|
scope: ScopeId,
|
||||||
|
mutations: &mut Mutations,
|
||||||
|
) -> usize {
|
||||||
|
let new_id = self.next_element(template, template.template.node_paths[idx]);
|
||||||
|
|
||||||
|
// Set the placeholder of the component
|
||||||
|
component.placeholder.set(Some(new_id));
|
||||||
|
|
||||||
|
// Set the placeholder of the scope
|
||||||
|
self.scopes[scope.0].placeholder.set(Some(new_id));
|
||||||
|
|
||||||
|
// Since the placeholder is already in the DOM, we don't create any new nodes
|
||||||
|
mutations.push(AssignId {
|
||||||
|
id: new_id,
|
||||||
|
path: &template.template.node_paths[idx][1..],
|
||||||
|
});
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::Arguments,
|
fmt::Arguments,
|
||||||
};
|
};
|
||||||
@@ -130,7 +129,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum RenderReturn<'a> {
|
pub enum RenderReturn<'a> {
|
||||||
|
/// A currently-available element
|
||||||
Sync(Element<'a>),
|
Sync(Element<'a>),
|
||||||
|
|
||||||
|
/// An ongoing future that will resolve to a [`Element`]
|
||||||
Async(BumpBox<'a, dyn Future<Output = Element<'a>> + 'a>),
|
Async(BumpBox<'a, dyn Future<Output = Element<'a>> + 'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,10 @@ pub use crate::innerlude::{
|
|||||||
TemplateAttribute,
|
TemplateAttribute,
|
||||||
TemplateNode,
|
TemplateNode,
|
||||||
UiEvent,
|
UiEvent,
|
||||||
|
VComponent,
|
||||||
|
VFragment,
|
||||||
VNode,
|
VNode,
|
||||||
|
VText,
|
||||||
VirtualDom,
|
VirtualDom,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
|
||||||
|
|
||||||
use futures_task::ArcWake;
|
|
||||||
use slab::Slab;
|
|
||||||
use std::future::Future;
|
|
||||||
|
|
||||||
use crate::{innerlude::Mutation, ScopeId};
|
|
||||||
|
|
||||||
type Shared<T> = Rc<RefCell<T>>;
|
|
||||||
struct LocalTask {}
|
|
||||||
|
|
||||||
pub struct Fiber {
|
|
||||||
// The work-in progress of this suspended tree
|
|
||||||
pub mutations: Vec<Mutation<'static>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SchedulerHandle {
|
|
||||||
tasks: Shared<Slab<LocalTask>>,
|
|
||||||
suspended: Shared<Slab<LocalTask>>,
|
|
||||||
fibers: Shared<Slab<Fiber>>,
|
|
||||||
tx: futures_channel::mpsc::UnboundedSender<SchedulerMsg>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TaskEntry {}
|
|
||||||
|
|
||||||
struct LocalTaskWaker<T> {
|
|
||||||
future: T,
|
|
||||||
id: TaskId,
|
|
||||||
tx: futures_channel::mpsc::UnboundedSender<SchedulerMsg>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T> Send for LocalTaskWaker<T> {}
|
|
||||||
unsafe impl<T> Sync for LocalTaskWaker<T> {}
|
|
||||||
|
|
||||||
impl<T> ArcWake for LocalTaskWaker<T> {
|
|
||||||
fn wake(self: Arc<Self>) {
|
|
||||||
Self::wake_by_ref(&self)
|
|
||||||
}
|
|
||||||
fn wake_by_ref(arc_self: &Arc<Self>) {
|
|
||||||
arc_self
|
|
||||||
.tx
|
|
||||||
.unbounded_send(SchedulerMsg::TaskNotified(arc_self.id))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SchedulerHandle {
|
|
||||||
fn spawn(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
|
|
||||||
use futures_task::waker;
|
|
||||||
|
|
||||||
let tasks = self.tasks.borrow_mut();
|
|
||||||
let entry = tasks.vacant_entry();
|
|
||||||
let id = TaskId(entry.key());
|
|
||||||
|
|
||||||
let task = Arc::new(LocalTaskWaker {
|
|
||||||
future: fut,
|
|
||||||
id,
|
|
||||||
tx: self.tx.clone(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let local_task = waker(task.clone());
|
|
||||||
|
|
||||||
entry.insert(val);
|
|
||||||
|
|
||||||
//
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(&self, id: TaskId) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
any_props::AnyProps,
|
any_props::AnyProps,
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
bump_frame::BumpFrame,
|
bump_frame::BumpFrame,
|
||||||
|
factory::RenderReturn,
|
||||||
innerlude::{Scheduler, SchedulerMsg},
|
innerlude::{Scheduler, SchedulerMsg},
|
||||||
lazynodes::LazyNodes,
|
lazynodes::LazyNodes,
|
||||||
nodes::VNode,
|
nodes::VNode,
|
||||||
@@ -116,7 +117,7 @@ impl ScopeState {
|
|||||||
/// Get a handle to the currently active head node arena for this Scope
|
/// Get a handle to the currently active head node arena for this Scope
|
||||||
///
|
///
|
||||||
/// This is useful for traversing the tree outside of the VirtualDom, such as in a custom renderer or in SSR.
|
/// This is useful for traversing the tree outside of the VirtualDom, such as in a custom renderer or in SSR.
|
||||||
pub fn root_node<'a>(&'a self) -> &'a VNode<'a> {
|
pub fn root_node<'a>(&'a self) -> &'a RenderReturn<'a> {
|
||||||
let r = unsafe { &*self.current_frame().node.get() };
|
let r = unsafe { &*self.current_frame().node.get() };
|
||||||
unsafe { std::mem::transmute(r) }
|
unsafe { std::mem::transmute(r) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::cache::Segment;
|
use super::cache::Segment;
|
||||||
use dioxus_core::{prelude::*, AttributeValue, DynamicNode};
|
use dioxus_core::{prelude::*, AttributeValue, DynamicNode, VText};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -18,7 +18,7 @@ impl SsrRender {
|
|||||||
let root = scope.root_node();
|
let root = scope.root_node();
|
||||||
|
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
self.render_template(&mut out, dom, root).unwrap();
|
// self.render_template(&mut out, dom, root).unwrap();
|
||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
@@ -46,32 +46,37 @@ impl SsrRender {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
Segment::Node(idx) => match &template.dynamic_nodes[*idx] {
|
Segment::Node(idx) => match &template.dynamic_nodes[*idx] {
|
||||||
DynamicNode::Text { value, inner, .. } => {
|
DynamicNode::Component(_) => todo!(),
|
||||||
// in SSR, we are concerned that we can't hunt down the right text node since they might get merged
|
DynamicNode::Text(_) => todo!(),
|
||||||
if !*inner {
|
DynamicNode::Fragment(_) => todo!(),
|
||||||
write!(buf, "<!--#-->")?;
|
DynamicNode::Placeholder(_) => todo!(),
|
||||||
}
|
// todo!()
|
||||||
|
// DynamicNode::Text(VText { id, value }) => {
|
||||||
|
// // in SSR, we are concerned that we can't hunt down the right text node since they might get merged
|
||||||
|
// // if !*inner {
|
||||||
|
// write!(buf, "<!--#-->")?;
|
||||||
|
// // }
|
||||||
|
|
||||||
// todo: escape the text
|
// // todo: escape the text
|
||||||
write!(buf, "{}", value)?;
|
// write!(buf, "{}", value)?;
|
||||||
|
|
||||||
if !*inner {
|
// // if !*inner {
|
||||||
write!(buf, "<!--/#-->")?;
|
// write!(buf, "<!--/#-->")?;
|
||||||
}
|
// // }
|
||||||
}
|
// }
|
||||||
DynamicNode::Fragment { nodes, .. } => {
|
// DynamicNode::Fragment { nodes, .. } => {
|
||||||
for child in *nodes {
|
// for child in *nodes {
|
||||||
self.render_template(buf, dom, child)?;
|
// self.render_template(buf, dom, child)?;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
DynamicNode::Component { scope, .. } => {
|
// DynamicNode::Component { scope, .. } => {
|
||||||
let id = scope.get().unwrap();
|
// let id = scope.get().unwrap();
|
||||||
let scope = dom.get_scope(id).unwrap();
|
// let scope = dom.get_scope(id).unwrap();
|
||||||
self.render_template(buf, dom, scope.root_node())?;
|
// self.render_template(buf, dom, scope.root_node())?;
|
||||||
}
|
// }
|
||||||
DynamicNode::Placeholder(_el) => {
|
// DynamicNode::Placeholder(_el) => {
|
||||||
write!(buf, "<!--placeholder-->")?;
|
// write!(buf, "<!--placeholder-->")?;
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
Segment::PreRendered(contents) => buf.push_str(contents),
|
Segment::PreRendered(contents) => buf.push_str(contents),
|
||||||
@@ -107,24 +112,24 @@ fn to_string_works() {
|
|||||||
|
|
||||||
use Segment::*;
|
use Segment::*;
|
||||||
|
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
StringCache::from_template(&dom.base_scope().root_node())
|
// StringCache::from_template(&dom.base_scope().root_node())
|
||||||
.unwrap()
|
// .unwrap()
|
||||||
.segments,
|
// .segments,
|
||||||
vec![
|
// vec![
|
||||||
PreRendered("<div class=\"asdasdasd\" class=\"asdasdasd\"".into(),),
|
// PreRendered("<div class=\"asdasdasd\" class=\"asdasdasd\"".into(),),
|
||||||
Attr(0,),
|
// Attr(0,),
|
||||||
PreRendered(">Hello world 1 -->".into(),),
|
// PreRendered(">Hello world 1 -->".into(),),
|
||||||
Node(0,),
|
// Node(0,),
|
||||||
PreRendered("<-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div>".into(),),
|
// PreRendered("<-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div>".into(),),
|
||||||
Node(1,),
|
// Node(1,),
|
||||||
Node(2,),
|
// Node(2,),
|
||||||
PreRendered("</div>".into(),),
|
// PreRendered("</div>".into(),),
|
||||||
]
|
// ]
|
||||||
);
|
// );
|
||||||
|
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
SsrRender::default().render_vdom(&dom),
|
// SsrRender::default().render_vdom(&dom),
|
||||||
"<div class=\"asdasdasd\" class=\"asdasdasd\" id=\"id-123\">Hello world 1 --><!--#-->123<!--/#--><-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div><!--#--></diiiiiiiiv><!--/#--><div><!--#-->finalize 0<!--/#--></div><div><!--#-->finalize 1<!--/#--></div><div><!--#-->finalize 2<!--/#--></div><div><!--#-->finalize 3<!--/#--></div><div><!--#-->finalize 4<!--/#--></div></div>"
|
// "<div class=\"asdasdasd\" class=\"asdasdasd\" id=\"id-123\">Hello world 1 --><!--#-->123<!--/#--><-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div><!--#--></diiiiiiiiv><!--/#--><div><!--#-->finalize 0<!--/#--></div><div><!--#-->finalize 1<!--/#--></div><div><!--#-->finalize 2<!--/#--></div><div><!--#-->finalize 3<!--/#--></div><div><!--#-->finalize 4<!--/#--></div></div>"
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user