feat: support cached ssr

This commit is contained in:
Jonathan Kelley committed 2022-11-02 01:00:37 -07:00
1 parent 4a31b29703
commit b6c0bce89c
11 files changed
+433 -178

No files matched your search

+6 -4
View File
@@ -3,6 +3,7 @@ use crate::mutations::Mutation::*;
use crate::nodes::VNode;
use crate::nodes::{DynamicNode, DynamicNodeKind, TemplateNode};
use crate::virtualdom::VirtualDom;
use crate::TemplateAttribute;
impl VirtualDom {
/// Create this template and write its mutations
@@ -112,10 +113,11 @@ impl VirtualDom {
id,
});
mutations.extend(attrs.into_iter().map(|attr| SetAttribute {
name: attr.name,
value: attr.value,
id,
mutations.extend(attrs.into_iter().filter_map(|attr| match attr {
TemplateAttribute::Static { name, value, .. } => {
Some(SetAttribute { name, value, id })
}
_ => None,
}));
children
+26 -9
View File
@@ -1,19 +1,36 @@
use std::fmt::Arguments;
use std::{cell::Cell, fmt::Arguments};
use crate::{innerlude::DynamicNode, LazyNodes, ScopeState, VNode};
use crate::{
arena::ElementId,
innerlude::{DynamicNode, DynamicNodeKind},
LazyNodes, ScopeState, VNode,
};
impl ScopeState {
/// Create some text that's allocated along with the other vnodes
///
pub fn text(&self, args: Arguments) -> DynamicNode {
// let (text, _is_static) = self.raw_text(args);
pub fn text<'a>(&'a self, args: Arguments) -> DynamicNode<'a> {
let (text, _) = self.raw_text(args);
// VNode::Text(self.bump.alloc(VText {
// text,
// id: Default::default(),
// }))
DynamicNode {
kind: DynamicNodeKind::Text {
id: Cell::new(ElementId(0)),
value: text,
},
path: &[0],
}
}
todo!()
pub fn raw_text<'a>(&'a self, args: Arguments) -> (&'a str, bool) {
match args.as_str() {
Some(static_str) => (static_str, true),
None => {
use bumpalo::core_alloc::fmt::Write;
let mut str_buf = bumpalo::collections::String::new_in(self.bump());
str_buf.write_fmt(args).unwrap();
(str_buf.into_bump_str(), false)
}
}
}
pub fn fragment_from_iter<'a, I, F: IntoVnode<'a, I>>(
+5 -2
View File
@@ -69,6 +69,8 @@ pub use crate::innerlude::{
// AnyAttributeValue, AnyEvent, Attribute, AttributeValue, Component, Element, ElementId,
Attribute,
AttributeValue,
DynamicNode,
DynamicNodeKind,
Element,
EventPriority,
LazyNodes,
@@ -94,8 +96,9 @@ pub use crate::innerlude::{
/// This includes types like [`Scope`], [`Element`], and [`Component`].
pub mod prelude {
pub use crate::innerlude::{
Attribute, Element, EventPriority, LazyNodes, Listener, NodeFactory, Scope, ScopeId,
ScopeState, TaskId, Template, TemplateAttribute, TemplateNode, UiEvent, VNode, VirtualDom,
Attribute, DynamicNode, DynamicNodeKind, Element, EventPriority, LazyNodes, Listener,
NodeFactory, Scope, ScopeId, ScopeState, TaskId, Template, TemplateAttribute, TemplateNode,
UiEvent, VNode, VirtualDom,
};
}
+1 -1
View File
@@ -34,8 +34,8 @@ pub enum Mutation<'a> {
},
ReplacePlaceholder {
path: &'static [u8],
m: usize,
path: &'static [u8],
},
AssignId {
+41 -16
View File
@@ -1,9 +1,5 @@
use crate::{any_props::AnyProps, arena::ElementId};
use std::{
any::{Any, TypeId},
cell::Cell,
num::NonZeroUsize,
};
use std::{any::Any, cell::Cell, hash::Hasher};
pub type TemplateId = &'static str;
@@ -15,7 +11,7 @@ pub struct VNode<'a> {
// When rendered, this template will be linked to its parent
pub parent: Option<(*mut VNode<'static>, usize)>,
pub template: Template,
pub template: Template<'static>,
pub root_ids: &'a [Cell<ElementId>],
@@ -26,15 +22,38 @@ pub struct VNode<'a> {
}
#[derive(Debug, Clone, Copy)]
pub struct Template {
pub id: &'static str,
pub roots: &'static [TemplateNode<'static>],
pub struct Template<'a> {
pub id: &'a str,
pub roots: &'a [TemplateNode<'a>],
}
impl<'a> std::hash::Hash for Template<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl PartialEq for Template<'_> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Template<'_> {}
impl PartialOrd for Template<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.id.partial_cmp(other.id)
}
}
impl Ord for Template<'_> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.id.cmp(other.id)
}
}
/// A weird-ish variant of VNodes with way more limited types
#[derive(Debug, Clone, Copy)]
pub enum TemplateNode<'a> {
/// A simple element
Element {
tag: &'a str,
namespace: Option<&'a str>,
@@ -62,7 +81,7 @@ pub enum DynamicNodeKind<'a> {
// Comes in with string interpolation or from format_args, include_str, etc
Text {
id: Cell<ElementId>,
value: &'static str,
value: &'a str,
},
// Anything that's coming in as an iterator
@@ -72,11 +91,17 @@ pub enum DynamicNodeKind<'a> {
}
#[derive(Debug)]
pub struct TemplateAttribute<'a> {
pub name: &'static str,
pub value: &'a str,
pub namespace: Option<&'static str>,
pub volatile: bool,
pub enum TemplateAttribute<'a> {
Static {
name: &'static str,
value: &'a str,
namespace: Option<&'static str>,
volatile: bool,
},
Dynamic {
name: &'static str,
index: usize,
},
}
pub struct AttributeLocation<'a> {
+9 -1
View File
@@ -15,7 +15,7 @@ use slab::Slab;
use std::collections::{BTreeSet, HashMap};
pub struct VirtualDom {
pub(crate) templates: HashMap<TemplateId, Template>,
pub(crate) templates: HashMap<TemplateId, Template<'static>>,
pub(crate) elements: Slab<ElementPath>,
pub(crate) scopes: Slab<ScopeState>,
pub(crate) scope_stack: Vec<ScopeId>,
@@ -82,6 +82,14 @@ impl VirtualDom {
///
/// This is cancel safe, so if the future is dropped, you can push events into the virtualdom
pub async fn wait_for_work(&mut self) {}
pub fn get_scope(&self, id: ScopeId) -> Option<&ScopeState> {
self.scopes.get(id.0)
}
pub fn base_scope(&self) -> &ScopeState {
self.scopes.get(0).unwrap()
}
}
impl Drop for VirtualDom {