From 4d6db0d887f4d49b2470d0515ce935345958266a Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Tue, 11 Aug 2026 19:12:42 +0530 Subject: [PATCH] fix(csr): consume document binding metadata --- packages/csr/src/reactive-runtime.ts | 14 ++++++++++++++ packages/csr/test/reactive.test.ts | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/packages/csr/src/reactive-runtime.ts b/packages/csr/src/reactive-runtime.ts index 371ea3d1..06ef7cd5 100644 --- a/packages/csr/src/reactive-runtime.ts +++ b/packages/csr/src/reactive-runtime.ts @@ -3537,6 +3537,20 @@ export const REACTIVE_RUNTIME = String.raw` function hydrateScopes(root) { var host = root || document; + // The document shell can contain server-resolved attributes such as + // lang={language} and data-theme={theme}. It has no component scope and + // therefore no client-side binding to retain; consume its compiler markers + // separately from component hydration. + if (host === document || host === document.documentElement) { + Array.prototype.slice + .call(document.documentElement.attributes) + .forEach(function (attribute) { + if (attribute.name.indexOf("data-wrn-bind-") === 0) { + document.documentElement.removeAttribute(attribute.name); + } + }); + } + var scopeSelector = "[data-scope], [data-wrn-scope]"; diff --git a/packages/csr/test/reactive.test.ts b/packages/csr/test/reactive.test.ts index eb245c1c..f311346c 100644 --- a/packages/csr/test/reactive.test.ts +++ b/packages/csr/test/reactive.test.ts @@ -549,6 +549,25 @@ test("hydration consumes private scope, behavior, and binding metadata", () => { expect(button.getAttribute("aria-expanded")).toBe("true"); }); +test("hydration removes server-resolved document binding metadata", () => { + const win = mount(`
Document content
`); + const root = win.document.documentElement; + root.setAttribute("lang", "en"); + root.setAttribute("data-theme", "dark"); + root.setAttribute("data-wrn-bind-0", '["lang","{language}"]'); + root.setAttribute("data-wrn-bind-1", '["data-theme","{theme}"]'); + + const runtime = win as unknown as { + __wrnexusHydrateScopes?: (root: unknown) => void; + }; + runtime.__wrnexusHydrateScopes?.(win.document); + + expect(root.getAttribute("lang")).toBe("en"); + expect(root.getAttribute("data-theme")).toBe("dark"); + expect(root.hasAttribute("data-wrn-bind-0")).toBe(false); + expect(root.hasAttribute("data-wrn-bind-1")).toBe(false); +}); + test("compiled client functions are not overwritten by fallback behavior parsing", () => { const behavior = Buffer.from( JSON.stringify({