fix(csr): consume hydration metadata from live DOM
This commit is contained in:
@@ -823,7 +823,12 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
|
||||
function setupScope(el) {
|
||||
if (el.__wrnexusScope) return;
|
||||
if (el.__wrnexusScope) {
|
||||
el.removeAttribute("data-scope");
|
||||
el.removeAttribute("data-wrn-scope");
|
||||
el.removeAttribute("data-wrn-behavior");
|
||||
return;
|
||||
}
|
||||
|
||||
el.__wrnexusScope = true;
|
||||
el.__wrnexusHydrated = true;
|
||||
@@ -1417,20 +1422,44 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
// that received the slot and continuing the search from its mount point.
|
||||
// The loop repeats so slots nested through several components resolve to
|
||||
// the scope that actually wrote the markup.
|
||||
function isScopeRoot(node) {
|
||||
return !!(
|
||||
node &&
|
||||
node.nodeType === 1 &&
|
||||
(node.__wrnexusScope ||
|
||||
node.hasAttribute("data-scope") ||
|
||||
node.hasAttribute("data-wrn-scope"))
|
||||
);
|
||||
}
|
||||
|
||||
function closestScope(node) {
|
||||
for (var current = node; current; current = current.parentNode) {
|
||||
if (isScopeRoot(current)) return current;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function closestScopeOrSlot(node) {
|
||||
for (var current = node; current; current = current.parentNode) {
|
||||
if (
|
||||
current.nodeType === 1 &&
|
||||
(current.hasAttribute("data-wrn-slot") || isScopeRoot(current))
|
||||
) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function ownerScope(node) {
|
||||
var cursor = node.nodeType === 1 ? node : node.parentNode;
|
||||
for (var guard = 0; cursor && cursor.closest && guard < 32; guard++) {
|
||||
var found = cursor.closest(
|
||||
"[data-scope], [data-wrn-scope], [data-wrn-slot]",
|
||||
);
|
||||
for (var guard = 0; cursor && guard < 32; guard++) {
|
||||
var found = closestScopeOrSlot(cursor);
|
||||
if (!found) return null;
|
||||
if (!found.hasAttribute("data-wrn-slot")) return found;
|
||||
// Step out of the component whose slot this content filled, then keep
|
||||
// looking from just above that component's root.
|
||||
var componentRoot =
|
||||
found.parentNode && found.parentNode.closest
|
||||
? found.parentNode.closest("[data-scope], [data-wrn-scope]")
|
||||
: null;
|
||||
var componentRoot = closestScope(found.parentNode);
|
||||
cursor = componentRoot ? componentRoot.parentNode : found.parentNode;
|
||||
}
|
||||
return null;
|
||||
@@ -1658,6 +1687,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
"data-wrn-bind-",
|
||||
) === 0
|
||||
) {
|
||||
node.removeAttribute(attribute.name);
|
||||
var binding;
|
||||
|
||||
try {
|
||||
@@ -2354,6 +2384,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
return;
|
||||
}
|
||||
|
||||
node.removeAttribute(marker.name);
|
||||
var binding;
|
||||
|
||||
try {
|
||||
@@ -2538,8 +2569,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
Array.prototype.slice
|
||||
.call(el.querySelectorAll("[data-wrn-events]"))
|
||||
.forEach(function (node) {
|
||||
var componentRoot =
|
||||
node.closest("[data-scope], [data-wrn-scope]");
|
||||
var componentRoot = closestScope(node);
|
||||
if (!componentRoot || componentRoot === el) return;
|
||||
// Only the scope that mounted this component owns its outputs.
|
||||
if (
|
||||
@@ -2615,7 +2645,8 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
// server forwards these markers onto the rendered child root; evaluate
|
||||
// them here and write changes into the child's prop signals.
|
||||
Array.prototype.slice
|
||||
.call(el.querySelectorAll("[data-scope], [data-wrn-scope]"))
|
||||
.call(el.querySelectorAll("*"))
|
||||
.filter(isScopeRoot)
|
||||
.forEach(function (node) {
|
||||
if (!node.parentNode || ownerScope(node.parentNode) !== el) return;
|
||||
Array.prototype.slice.call(node.attributes).forEach(function (attr) {
|
||||
@@ -2742,16 +2773,25 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
|
||||
renderAll();
|
||||
|
||||
// Hydration metadata is an SSR transport format, not application DOM.
|
||||
// All values needed after setup now live in closures, WeakMaps, or private
|
||||
// element properties, so keep the live DOM limited to actual web markup.
|
||||
el.removeAttribute("data-scope");
|
||||
el.removeAttribute("data-wrn-scope");
|
||||
el.removeAttribute("data-wrn-behavior");
|
||||
}
|
||||
|
||||
function disposeBehaviors(root) {
|
||||
var elements = [];
|
||||
if (root && root.nodeType === 1 && root.hasAttribute("data-wrn-behavior")) {
|
||||
elements.push(root);
|
||||
}
|
||||
if (root && root.querySelectorAll) {
|
||||
Array.prototype.push.apply(elements, root.querySelectorAll("[data-wrn-behavior]"));
|
||||
}
|
||||
mountedBehaviorRoots.forEach(function (element) {
|
||||
if (
|
||||
element === root ||
|
||||
(root && root.nodeType === 1 && root.contains && root.contains(element))
|
||||
) {
|
||||
elements.push(element);
|
||||
}
|
||||
});
|
||||
elements.reverse().forEach(function (element) {
|
||||
var instance = behaviorInstances.get(element);
|
||||
if (instance) instance.dispose();
|
||||
|
||||
Reference in New Issue
Block a user