From 1cda2a01b31d5028527d53aba4ce27ea028097bf Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Sun, 19 Jul 2026 12:03:49 +0530 Subject: [PATCH] release: WRNexusJS 0.2.49 --- packages/compiler/test/compiler.test.ts | 18 ++--- packages/csr/src/reactive-runtime.ts | 94 +++++++++++-------------- 2 files changed, 50 insertions(+), 62 deletions(-) diff --git a/packages/compiler/test/compiler.test.ts b/packages/compiler/test/compiler.test.ts index 4386672e..41b68de6 100644 --- a/packages/compiler/test/compiler.test.ts +++ b/packages/compiler/test/compiler.test.ts @@ -881,7 +881,7 @@ component Accordion { expect(output).not.toContain('${(isOpen(index)) ? " open" : ""}'); }); -test("server-rendered each locals work in reactive handlers", () => { +test("server-rendered each locals work in reactive handlers", async () => { const firstLocals = Buffer.from( JSON.stringify({ item: { @@ -903,13 +903,12 @@ test("server-rendered each locals work in reactive handlers", () => { ).toString("base64"); const dom = mountHtml(` -
+
`); - const buttons: any = dom.querySelectorAll("button"); + const buttons = dom.querySelectorAll("button") as HTMLButtonElement[]; - buttons[1].click(); + buttons[1]!.click(); + + await Promise.resolve(); const articles = dom.querySelectorAll("article"); - expect(articles[0].querySelector("span")?.classList.contains("open")).toBe(false); + expect(articles[0]!.querySelector("span")?.classList.contains("open")).toBe(false); - expect(articles[1].querySelector("span")?.classList.contains("open")).toBe(true); + expect(articles[1]!.querySelector("span")?.classList.contains("open")).toBe(true); }); diff --git a/packages/csr/src/reactive-runtime.ts b/packages/csr/src/reactive-runtime.ts index 7a62c819..7079b5b7 100644 --- a/packages/csr/src/reactive-runtime.ts +++ b/packages/csr/src/reactive-runtime.ts @@ -214,59 +214,6 @@ export const REACTIVE_RUNTIME = String.raw` var value = initial; var subscribers = new Set(); var notifying = false; - var pendingNotification = false; - var pendingPrevious; - - function notify(previous) { - if (notifying) { - pendingNotification = true; - - if (pendingPrevious === undefined) { - pendingPrevious = previous; - } - - return; - } - - notifying = true; - - try { - /* - * Iterate a snapshot. Reactive renderers may subscribe again while - * running, but that must not mutate the collection currently being - * iterated. - */ - var snapshot = - Array.from(subscribers); - - snapshot.forEach(function ( - subscriber, - ) { - if ( - subscribers.has( - subscriber, - ) - ) { - subscriber( - value, - previous, - ); - } - }); - } finally { - notifying = false; - } - - if (pendingNotification) { - var nextPrevious = - pendingPrevious; - - pendingNotification = false; - pendingPrevious = undefined; - - notify(nextPrevious); - } - } return { get: function () { @@ -286,7 +233,46 @@ export const REACTIVE_RUNTIME = String.raw` var previous = value; value = nextValue; - notify(previous); + /* + * Prevent nested synchronous notification of the + * same signal. + */ + if (notifying) { + return; + } + + notifying = true; + + try { + /* + * Always iterate a snapshot. A renderer can read + * this signal and subscribe again while it runs. + */ + var snapshot = + Array.from(subscribers); + + for ( + var index = 0; + index < snapshot.length; + index++ + ) { + var subscriber = + snapshot[index]; + + if ( + subscribers.has( + subscriber, + ) + ) { + subscriber( + value, + previous, + ); + } + } + } finally { + notifying = false; + } }, subscribe: function (