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
@@ -31,7 +31,7 @@ export class BaseInterpreter {
|
||||
// sledgehammer is generating this...
|
||||
m: any;
|
||||
|
||||
constructor() { }
|
||||
constructor() {}
|
||||
|
||||
initialize(root: HTMLElement, handler: EventListener | null = null) {
|
||||
this.global = {};
|
||||
@@ -45,7 +45,7 @@ export class BaseInterpreter {
|
||||
this.handler = handler;
|
||||
|
||||
// make sure to set the root element's ID so it still registers events
|
||||
root.setAttribute('data-dioxus-id', "0");
|
||||
root.setAttribute("data-dioxus-id", "0");
|
||||
}
|
||||
|
||||
handleResizeEvent(entry: ResizeObserverEntry) {
|
||||
@@ -241,6 +241,18 @@ export class BaseInterpreter {
|
||||
NodeFilter.SHOW_COMMENT
|
||||
);
|
||||
|
||||
let nextSibling = under.nextSibling;
|
||||
// Continue to the next node. Returns false if we should stop traversing because we've reached the end of the children
|
||||
// of the root
|
||||
let continueToNextNode = () => {
|
||||
// stop traversing if there are no more nodes
|
||||
if (!treeWalker.nextNode()) {
|
||||
return false;
|
||||
}
|
||||
// stop traversing if we have reached the next sibling of the root node
|
||||
return treeWalker.currentNode !== nextSibling;
|
||||
};
|
||||
|
||||
while (treeWalker.currentNode) {
|
||||
const currentNode = treeWalker.currentNode as ChildNode;
|
||||
if (currentNode.nodeType === Node.COMMENT_NODE) {
|
||||
@@ -251,7 +263,7 @@ export class BaseInterpreter {
|
||||
|
||||
if (placeholderSplit.length > 1) {
|
||||
this.nodes[ids[parseInt(placeholderSplit[1])]] = currentNode;
|
||||
if (!treeWalker.nextNode()) {
|
||||
if (!continueToNextNode()) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
@@ -284,7 +296,9 @@ export class BaseInterpreter {
|
||||
}
|
||||
treeWalker.currentNode = commentAfterText;
|
||||
this.nodes[ids[parseInt(textNodeSplit[1])]] = textNode;
|
||||
let exit = !treeWalker.nextNode();
|
||||
// Stop traversing if we started on a comment node (which has no children)
|
||||
// or the next sibling stops the walk
|
||||
let exit = currentNode === under || !continueToNextNode();
|
||||
// remove the comment node after the text node
|
||||
commentAfterText.remove();
|
||||
if (exit) {
|
||||
@@ -293,7 +307,7 @@ export class BaseInterpreter {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!treeWalker.nextNode()) {
|
||||
if (!continueToNextNode()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import "./hydrate_types";
|
||||
import { HydrationCallback } from "./hydrate_types";
|
||||
|
||||
export function register_rehydrate_chunk_for_streaming(
|
||||
callback: (id: number[], data: Uint8Array) => void
|
||||
export function register_rehydrate_chunk_for_streaming(callback: HydrationCallback): void {
|
||||
return register_rehydrate_chunk_for_streaming_debug(callback);
|
||||
}
|
||||
|
||||
export function register_rehydrate_chunk_for_streaming_debug(
|
||||
callback: HydrationCallback
|
||||
): void {
|
||||
window.hydration_callback = callback;
|
||||
for (let i = 0; i < window.hydrate_queue.length; i++) {
|
||||
const [id, data] = window.hydrate_queue[i];
|
||||
window.hydration_callback(id, data);
|
||||
const [id, data, debug_types, debug_locations] = window.hydrate_queue[i];
|
||||
window.hydration_callback(id, data, debug_types, debug_locations);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,17 @@
|
||||
export {};
|
||||
export { };
|
||||
|
||||
export type HydrationCallback = (
|
||||
id: number[],
|
||||
data: Uint8Array,
|
||||
debug_types: string[] | null,
|
||||
debug_locations: string[] | null
|
||||
) => void;
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
hydrate_queue: [number[], Uint8Array][];
|
||||
hydration_callback: null | ((id: number[], data: Uint8Array) => void);
|
||||
hydrate_queue: [number[], Uint8Array, string[] | null, string[] | null][];
|
||||
hydration_callback:
|
||||
| null
|
||||
| HydrationCallback;
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,18 @@ import "./hydrate_types";
|
||||
window.hydrate_queue = [];
|
||||
|
||||
// @ts-ignore
|
||||
window.dx_hydrate = (id: number[], data: string) => {
|
||||
window.dx_hydrate = (
|
||||
id: number[],
|
||||
data: string,
|
||||
debug_types: string[] | null,
|
||||
debug_locations: string[] | null
|
||||
) => {
|
||||
// First convert the base64 encoded string to a Uint8Array
|
||||
const decoded = atob(data);
|
||||
const bytes = Uint8Array.from(decoded, (c) => c.charCodeAt(0));
|
||||
if (window.hydration_callback) {
|
||||
window.hydration_callback(id, bytes);
|
||||
window.hydration_callback(id, bytes, debug_types, debug_locations);
|
||||
} else {
|
||||
window.hydrate_queue.push([id, bytes]);
|
||||
window.hydrate_queue.push([id, bytes, debug_types, debug_locations]);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user