From 5fcc3923025dc1503f1e39a187057a164dbd2533 Mon Sep 17 00:00:00 2001 From: Helen Kwok <107752876+helenkwok@users.noreply.github.com> Date: Fri, 30 Oct 2026 05:00:10 +1030 Subject: [PATCH] craft-web-host: Fn listeners, so a nested event reaches the queue wasm-bindgen throws "closure invoked recursively" when an FnMut closure is called while it runs, before its body can queue the message. The listeners only read their captures, so they are Fn; the handler's state stays behind the Inbox's RefCell. --- crates/web-host/src/web.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/web-host/src/web.rs b/crates/web-host/src/web.rs index e86df4de..969a79e5 100644 --- a/crates/web-host/src/web.rs +++ b/crates/web-host/src/web.rs @@ -92,14 +92,17 @@ impl Host { } } - /// Hear the host's messages for this app. The listener lives as long as the page. + /// Hear the host's messages for this app. The listener lives as long as the page. The + /// listeners are `Fn`: a page host can dispatch an event while one is still running (a + /// `saved` for the `save` the handler just posted), and wasm-bindgen refuses to re-enter an + /// `FnMut` closure before its body runs, so the message would never reach the queue. pub fn listen(&self, handler: impl FnMut(Message) + 'static) { let app = self.app; let inbox = Rc::new(Inbox::new(handler)); match &self.transport { Transport::Parent { window, parent, origin } => { let (parent, origin, inbox) = (parent.clone(), origin.clone(), inbox.clone()); - let on_message = Closure::::new(move |event: web_sys::MessageEvent| { + let on_message = Closure::::new(move |event: web_sys::MessageEvent| { if event.origin() != origin || !event.source().is_some_and(|s| js_sys::Object::is(&s, &parent)) { return; } @@ -116,7 +119,7 @@ impl Host { Transport::Page { canvas } => { for kind in Incoming::ALL { let inbox = inbox.clone(); - let on_event = Closure::::new(move |event: web_sys::CustomEvent| { + let on_event = Closure::::new(move |event: web_sys::CustomEvent| { if let Some(message) = read(kind, &event.detail()) { inbox.deliver(message); }