Skip to content

Commit

Permalink
feat: create_blocking_resource (#752)
Browse files Browse the repository at this point in the history
  • Loading branch information
gbj authored Apr 1, 2023
1 parent a3327f8 commit e78ce7e
Show file tree
Hide file tree
Showing 6 changed files with 387 additions and 153 deletions.
83 changes: 51 additions & 32 deletions leptos_dom/src/ssr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ pub fn render_to_stream_with_prefix_undisposed_with_context(
let runtime = create_runtime();

let (
(shell, prefix, pending_resources, pending_fragments, serializers),
(shell, pending_resources, pending_fragments, serializers),
scope,
disposer,
) = run_scope_undisposed(runtime, {
Expand All @@ -146,57 +146,44 @@ pub fn render_to_stream_with_prefix_undisposed_with_context(

let resources = cx.pending_resources();
let pending_resources = serde_json::to_string(&resources).unwrap();
let prefix = prefix(cx);

(
shell,
prefix,
pending_resources,
cx.pending_fragments(),
cx.serialization_resolvers(),
)
}
});
let cx = Scope { runtime, id: scope };

let blocking_fragments = FuturesUnordered::new();
let fragments = FuturesUnordered::new();
for (fragment_id, (fut, _)) in pending_fragments {
fragments.push(async move { (fragment_id, fut.await) })

for (fragment_id, data) in pending_fragments {
if data.should_block {
blocking_fragments
.push(async move { (fragment_id, data.out_of_order.await) });
} else {
fragments
.push(async move { (fragment_id, data.out_of_order.await) });
}
}

// resources and fragments
// stream HTML for each <Suspense/> as it resolves
// TODO can remove id_before_suspense entirely now
let fragments = fragments.map(|(fragment_id, html)| {
format!(
r#"
<template id="{fragment_id}f">{html}</template>
<script>
var id = "{fragment_id}";
var open;
var close;
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT);
while(walker.nextNode()) {{
if(walker.currentNode.textContent == `suspense-open-${{id}}`) {{
open = walker.currentNode;
}} else if(walker.currentNode.textContent == `suspense-close-${{id}}`) {{
close = walker.currentNode;
}}
}}
var range = new Range();
range.setStartAfter(open);
range.setEndBefore(close);
range.deleteContents();
var tpl = document.getElementById("{fragment_id}f");
close.parentNode.insertBefore(tpl.content.cloneNode(true), close);
</script>
"#
)
});
let fragments = fragments_to_chunks(fragments);
// stream data for each Resource as it resolves
let resources = render_serializers(serializers);

// HTML for the view function and script to store resources
let stream = futures::stream::once(async move {
let mut blocking = String::new();
let mut blocking_fragments = fragments_to_chunks(blocking_fragments);
while let Some(fragment) = blocking_fragments.next().await {
blocking.push_str(&fragment);
}
let prefix = prefix(cx);
format!(
r#"
{prefix}
Expand All @@ -206,6 +193,7 @@ pub fn render_to_stream_with_prefix_undisposed_with_context(
__LEPTOS_RESOLVED_RESOURCES = new Map();
__LEPTOS_RESOURCE_RESOLVERS = new Map();
</script>
{blocking}
"#
)
})
Expand All @@ -222,6 +210,37 @@ pub fn render_to_stream_with_prefix_undisposed_with_context(
(stream, runtime, scope)
}

fn fragments_to_chunks(
fragments: impl Stream<Item = (String, String)>,
) -> impl Stream<Item = String> {
fragments.map(|(fragment_id, html)| {
format!(
r#"
<template id="{fragment_id}f">{html}</template>
<script>
var id = "{fragment_id}";
var open;
var close;
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT);
while(walker.nextNode()) {{
if(walker.currentNode.textContent == `suspense-open-${{id}}`) {{
open = walker.currentNode;
}} else if(walker.currentNode.textContent == `suspense-close-${{id}}`) {{
close = walker.currentNode;
}}
}}
var range = new Range();
range.setStartAfter(open);
range.setEndBefore(close);
range.deleteContents();
var tpl = document.getElementById("{fragment_id}f");
close.parentNode.insertBefore(tpl.content.cloneNode(true), close);
</script>
"#
)
})
}

impl View {
/// Consumes the node and renders it into an HTML string.
pub fn render_to_string(self, _cx: Scope) -> Cow<'static, str> {
Expand Down
Loading

0 comments on commit e78ce7e

Please sign in to comment.