Fix hydration of suspense fragments that contain text nodes (#3287)
* Fix hydration of suspense fragments that contain text nodes * fix release builds * disable link deduplication * restore meta tag deduplication * Add a test for the failed hydration case * make changes to the document trait non-breaking * remove info log from server future hook * restore default implementation - this was also a breaking change * fix semver breakage * clean up server_future * Cleanup unused code * fix clippy --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
57d637184f
commit
d41ab3a756
33 files changed
+644
-222
No files matched your search
@@ -59,12 +59,13 @@ impl ServerDocument {
|
||||
|
||||
/// Write the head element into the serialized context for hydration
|
||||
/// We write true if the head element was written to the DOM during server side rendering
|
||||
#[track_caller]
|
||||
pub(crate) fn serialize_for_hydration(&self) {
|
||||
// We only serialize the head elements if the web document feature is enabled
|
||||
#[cfg(feature = "document")]
|
||||
{
|
||||
let serialize = crate::html_storage::serialize_context();
|
||||
serialize.push(&!self.0.borrow().streaming);
|
||||
serialize.push(&!self.0.borrow().streaming, std::panic::Location::caller());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,13 +77,10 @@ impl Document for ServerDocument {
|
||||
|
||||
fn set_title(&self, title: String) {
|
||||
self.warn_if_streaming();
|
||||
self.serialize_for_hydration();
|
||||
self.0.borrow_mut().title = Some(title);
|
||||
}
|
||||
|
||||
fn create_meta(&self, props: MetaProps) {
|
||||
self.warn_if_streaming();
|
||||
self.serialize_for_hydration();
|
||||
self.0.borrow_mut().meta.push(rsx! {
|
||||
meta {
|
||||
name: props.name,
|
||||
@@ -96,8 +94,6 @@ impl Document for ServerDocument {
|
||||
}
|
||||
|
||||
fn create_script(&self, props: ScriptProps) {
|
||||
self.warn_if_streaming();
|
||||
self.serialize_for_hydration();
|
||||
let children = props.script_contents().ok();
|
||||
self.0.borrow_mut().script.push(rsx! {
|
||||
script {
|
||||
@@ -117,42 +113,19 @@ impl Document for ServerDocument {
|
||||
}
|
||||
|
||||
fn create_style(&self, props: StyleProps) {
|
||||
self.warn_if_streaming();
|
||||
self.serialize_for_hydration();
|
||||
match (&props.href, props.style_contents()) {
|
||||
// The style has inline contents, render it as a style tag
|
||||
(_, Ok(contents)) => self.0.borrow_mut().script.push(rsx! {
|
||||
style {
|
||||
media: props.media,
|
||||
nonce: props.nonce,
|
||||
title: props.title,
|
||||
..props.additional_attributes,
|
||||
{contents}
|
||||
}
|
||||
}),
|
||||
// The style has a href, render it as a link tag
|
||||
(Some(_), _) => {
|
||||
self.0.borrow_mut().script.push(rsx! {
|
||||
link {
|
||||
rel: "stylesheet",
|
||||
href: props.href,
|
||||
media: props.media,
|
||||
nonce: props.nonce,
|
||||
title: props.title,
|
||||
..props.additional_attributes,
|
||||
}
|
||||
});
|
||||
let contents = props.style_contents().ok();
|
||||
self.0.borrow_mut().script.push(rsx! {
|
||||
style {
|
||||
media: props.media,
|
||||
nonce: props.nonce,
|
||||
title: props.title,
|
||||
..props.additional_attributes,
|
||||
{contents}
|
||||
}
|
||||
// The style has neither contents nor src, log an error
|
||||
(None, Err(err)) => {
|
||||
err.log("Style");
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn create_link(&self, props: LinkProps) {
|
||||
self.warn_if_streaming();
|
||||
self.serialize_for_hydration();
|
||||
self.0.borrow_mut().link.push(rsx! {
|
||||
link {
|
||||
rel: props.rel,
|
||||
@@ -172,4 +145,10 @@ impl Document for ServerDocument {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn create_head_component(&self) -> bool {
|
||||
self.warn_if_streaming();
|
||||
self.serialize_for_hydration();
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#![allow(unused)]
|
||||
//! On the client, we use the [`WebDocument`] implementation to render the head for any elements that were not rendered on the server.
|
||||
|
||||
use dioxus_lib::document::*;
|
||||
use dioxus_lib::{document::*, prelude::queue_effect};
|
||||
use dioxus_web::WebDocument;
|
||||
|
||||
fn head_element_written_on_server() -> bool {
|
||||
@@ -12,6 +12,7 @@ fn head_element_written_on_server() -> bool {
|
||||
}
|
||||
|
||||
/// A document provider for fullstack web clients
|
||||
#[derive(Clone)]
|
||||
pub struct FullstackWebDocument;
|
||||
|
||||
impl Document for FullstackWebDocument {
|
||||
@@ -19,38 +20,32 @@ impl Document for FullstackWebDocument {
|
||||
WebDocument.eval(js)
|
||||
}
|
||||
|
||||
/// Set the title of the document
|
||||
fn set_title(&self, title: String) {
|
||||
if head_element_written_on_server() {
|
||||
return;
|
||||
}
|
||||
WebDocument.set_title(title);
|
||||
}
|
||||
|
||||
/// Create a new meta tag in the head
|
||||
fn create_meta(&self, props: MetaProps) {
|
||||
if head_element_written_on_server() {
|
||||
return;
|
||||
}
|
||||
WebDocument.create_meta(props);
|
||||
}
|
||||
|
||||
/// Create a new script tag in the head
|
||||
fn create_script(&self, props: ScriptProps) {
|
||||
if head_element_written_on_server() {
|
||||
return;
|
||||
}
|
||||
WebDocument.create_script(props);
|
||||
}
|
||||
|
||||
/// Create a new style tag in the head
|
||||
fn create_style(&self, props: StyleProps) {
|
||||
if head_element_written_on_server() {
|
||||
return;
|
||||
}
|
||||
WebDocument.create_style(props);
|
||||
}
|
||||
|
||||
/// Create a new link tag in the head
|
||||
fn create_link(&self, props: LinkProps) {
|
||||
if head_element_written_on_server() {
|
||||
return;
|
||||
}
|
||||
WebDocument.create_link(props);
|
||||
}
|
||||
|
||||
fn create_head_component(&self) -> bool {
|
||||
!head_element_written_on_server()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user