mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
feat: implement hydration for vraw (#3245)
This commit is contained in:
parent
998db3db44
commit
d0205a8ea3
@ -267,9 +267,7 @@ mod feat_hydration {
|
|||||||
VNode::VSuspense(vsuspense) => vsuspense
|
VNode::VSuspense(vsuspense) => vsuspense
|
||||||
.hydrate(root, parent_scope, parent, fragment)
|
.hydrate(root, parent_scope, parent, fragment)
|
||||||
.into(),
|
.into(),
|
||||||
VNode::VRaw(_) => {
|
VNode::VRaw(vraw) => vraw.hydrate(root, parent_scope, parent, fragment).into(),
|
||||||
panic!("VRaw is not hydratable (raw HTML string cannot be hydrated)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,6 +125,34 @@ impl Reconcilable for VRaw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "hydration")]
|
||||||
|
mod feat_hydration {
|
||||||
|
use super::*;
|
||||||
|
use crate::dom_bundle::{Fragment, Hydratable};
|
||||||
|
use crate::virtual_dom::Collectable;
|
||||||
|
|
||||||
|
impl Hydratable for VRaw {
|
||||||
|
fn hydrate(
|
||||||
|
self,
|
||||||
|
_root: &BSubtree,
|
||||||
|
_parent_scope: &AnyScope,
|
||||||
|
parent: &Element,
|
||||||
|
fragment: &mut Fragment,
|
||||||
|
) -> Self::Bundle {
|
||||||
|
let collectable = Collectable::Raw;
|
||||||
|
let fallback_fragment = Fragment::collect_between(fragment, &collectable, parent);
|
||||||
|
|
||||||
|
let Self { html } = self;
|
||||||
|
|
||||||
|
BRaw {
|
||||||
|
children_count: fallback_fragment.len(),
|
||||||
|
reference: fallback_fragment.iter().next().cloned(),
|
||||||
|
html,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|||||||
@ -64,6 +64,7 @@ mod feat_ssr_hydration {
|
|||||||
/// This indicates a kind that can be collected from fragment to be processed at a later time
|
/// This indicates a kind that can be collected from fragment to be processed at a later time
|
||||||
pub enum Collectable {
|
pub enum Collectable {
|
||||||
Component(ComponentName),
|
Component(ComponentName),
|
||||||
|
Raw,
|
||||||
Suspense,
|
Suspense,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +80,7 @@ mod feat_ssr_hydration {
|
|||||||
pub fn open_start_mark(&self) -> &'static str {
|
pub fn open_start_mark(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Component(_) => "<[",
|
Self::Component(_) => "<[",
|
||||||
|
Self::Raw => "<#",
|
||||||
Self::Suspense => "<?",
|
Self::Suspense => "<?",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,6 +88,7 @@ mod feat_ssr_hydration {
|
|||||||
pub fn close_start_mark(&self) -> &'static str {
|
pub fn close_start_mark(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Component(_) => "</[",
|
Self::Component(_) => "</[",
|
||||||
|
Self::Raw => "</#",
|
||||||
Self::Suspense => "</?",
|
Self::Suspense => "</?",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,6 +96,7 @@ mod feat_ssr_hydration {
|
|||||||
pub fn end_mark(&self) -> &'static str {
|
pub fn end_mark(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Component(_) => "]>",
|
Self::Component(_) => "]>",
|
||||||
|
Self::Raw => ">",
|
||||||
Self::Suspense => ">",
|
Self::Suspense => ">",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,6 +108,7 @@ mod feat_ssr_hydration {
|
|||||||
Self::Component(m) => format!("Component({m})").into(),
|
Self::Component(m) => format!("Component({m})").into(),
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
Self::Component(_) => "Component".into(),
|
Self::Component(_) => "Component".into(),
|
||||||
|
Self::Raw => "Raw".into(),
|
||||||
Self::Suspense => "Suspense".into(),
|
Self::Suspense => "Suspense".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +135,7 @@ mod feat_ssr {
|
|||||||
Self::Component(type_name) => {
|
Self::Component(type_name) => {
|
||||||
let _ = w.write_str(type_name);
|
let _ = w.write_str(type_name);
|
||||||
}
|
}
|
||||||
|
Self::Raw => {}
|
||||||
Self::Suspense => {}
|
Self::Suspense => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +152,7 @@ mod feat_ssr {
|
|||||||
Self::Component(type_name) => {
|
Self::Component(type_name) => {
|
||||||
let _ = w.write_str(type_name);
|
let _ = w.write_str(type_name);
|
||||||
}
|
}
|
||||||
|
Self::Raw => {}
|
||||||
Self::Suspense => {}
|
Self::Suspense => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,15 +19,26 @@ mod feat_ssr {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::html::AnyScope;
|
use crate::html::AnyScope;
|
||||||
use crate::platform::fmt::BufWriter;
|
use crate::platform::fmt::BufWriter;
|
||||||
|
use crate::virtual_dom::Collectable;
|
||||||
|
|
||||||
impl VRaw {
|
impl VRaw {
|
||||||
pub(crate) async fn render_into_stream(
|
pub(crate) async fn render_into_stream(
|
||||||
&self,
|
&self,
|
||||||
w: &mut BufWriter,
|
w: &mut BufWriter,
|
||||||
_parent_scope: &AnyScope,
|
_parent_scope: &AnyScope,
|
||||||
_hydratable: bool,
|
hydratable: bool,
|
||||||
) {
|
) {
|
||||||
|
let collectable = Collectable::Raw;
|
||||||
|
|
||||||
|
if hydratable {
|
||||||
|
collectable.write_open_tag(w);
|
||||||
|
}
|
||||||
|
|
||||||
let _ = w.write_str(self.html.as_ref());
|
let _ = w.write_str(self.html.as_ref());
|
||||||
|
|
||||||
|
if hydratable {
|
||||||
|
collectable.write_close_tag(w);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,8 @@ use web_sys::{HtmlElement, HtmlTextAreaElement};
|
|||||||
use yew::platform::time::sleep;
|
use yew::platform::time::sleep;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew::suspense::{use_future, Suspension, SuspensionResult};
|
use yew::suspense::{use_future, Suspension, SuspensionResult};
|
||||||
use yew::{Renderer, ServerRenderer};
|
use yew::virtual_dom::VNode;
|
||||||
|
use yew::{function_component, Renderer, ServerRenderer};
|
||||||
|
|
||||||
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
@ -94,6 +95,60 @@ async fn hydration_works() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
async fn hydration_with_raw() {
|
||||||
|
#[function_component(Content)]
|
||||||
|
fn content() -> Html {
|
||||||
|
let vnode = VNode::from_html_unchecked("<div><p>Hello World</p></div>".into());
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div class="content-area">
|
||||||
|
{vnode}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(App)]
|
||||||
|
fn app() -> Html {
|
||||||
|
html! {
|
||||||
|
<div id="result">
|
||||||
|
<Content />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = ServerRenderer::<App>::new().render().await;
|
||||||
|
|
||||||
|
gloo::utils::document()
|
||||||
|
.query_selector("#output")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.set_inner_html(&s);
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(10)).await;
|
||||||
|
|
||||||
|
Renderer::<App>::with_root(gloo::utils::document().get_element_by_id("output").unwrap())
|
||||||
|
.hydrate();
|
||||||
|
|
||||||
|
let result = obtain_result();
|
||||||
|
|
||||||
|
// still hydrating, during hydration, the server rendered result is shown.
|
||||||
|
assert_eq!(
|
||||||
|
result.as_str(),
|
||||||
|
r#"<!--<[hydration::hydration_with_raw::{{closure}}::Content]>--><div class="content-area"><!--<#>--><div><p>Hello World</p></div><!--</#>--></div><!--</[hydration::hydration_with_raw::{{closure}}::Content]>-->"#
|
||||||
|
);
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(50)).await;
|
||||||
|
|
||||||
|
let result = obtain_result();
|
||||||
|
|
||||||
|
// hydrated.
|
||||||
|
assert_eq!(
|
||||||
|
result.as_str(),
|
||||||
|
r#"<div class="content-area"><div><p>Hello World</p></div></div>"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
async fn hydration_with_suspense() {
|
async fn hydration_with_suspense() {
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user