From 223c687b42cc083f0b7f3311d954314a0d01cf9d Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:01:24 +0800 Subject: [PATCH 1/3] refactor: with WeakRef in element APIs and WASM bindings to improve memory management. --- .changeset/refactor-weakref-webcore.md | 5 +++ .../web-core/binary/client/client.d.ts | 8 +++-- .../binary/client/client_bg.wasm.d.ts | 3 +- .../web-core/binary/client_legacy/client.d.ts | 8 +++-- .../binary/client_legacy/client_bg.wasm.d.ts | 3 +- .../web-core/src/js_binding/mts_js_binding.rs | 33 ++++++++++++++----- .../client/element_apis/event_apis.rs | 8 ++--- .../client/element_apis/style_apis.rs | 21 +++++++++--- .../main_thread/client/main_thread_context.rs | 27 ++++++++++----- .../web-core/tests/element-apis.spec.ts | 4 +-- .../mainthread/elementAPIs/WASMJSBinding.ts | 30 ++++++++++++++--- .../elementAPIs/createElementAPI.ts | 16 ++++++++- .../web-core/ts/types/IMtsBinding.ts | 14 ++++++-- 13 files changed, 135 insertions(+), 45 deletions(-) create mode 100644 .changeset/refactor-weakref-webcore.md diff --git a/.changeset/refactor-weakref-webcore.md b/.changeset/refactor-weakref-webcore.md new file mode 100644 index 0000000000..3000a3f15b --- /dev/null +++ b/.changeset/refactor-weakref-webcore.md @@ -0,0 +1,5 @@ +--- +"@lynx-js/web-core": patch +--- + +refactor: with WeakRef in element APIs and WASM bindings to improve memory management. diff --git a/packages/web-platform/web-core/binary/client/client.d.ts b/packages/web-platform/web-core/binary/client/client.d.ts index 3557cc760a..9d23d7e787 100644 --- a/packages/web-platform/web-core/binary/client/client.d.ts +++ b/packages/web-platform/web-core/binary/client/client.d.ts @@ -22,15 +22,16 @@ export class MainThreadWasmContext { add_dataset(unique_id: number, key: any, value: any): void; add_run_worklet_event(unique_id: number, event_type: string, event_name: string, event_handler_identifier?: any | null): void; common_event_handler(event: any, bubble_unique_id_path: Uint32Array, event_name: string, is_bubble: boolean): void; - create_element_common(parent_component_unique_id: number, dom: HTMLElement, css_id?: number | null, component_id?: string | null): number; + create_element_common(parent_component_unique_id: number, dom: HTMLElement, dom_ref: WeakRef, css_id?: number | null, component_id?: string | null): number; dispatch_event_by_path(bubble_unique_id_path: Uint32Array, event_name: string, is_capture: boolean, serialized_event: any): boolean; dispatch_global_bind_event(bubble_unique_id_path: Uint32Array, event_name: string, serialized_event: any): void; + gc(): void; get_component_id(unique_id: number): string | undefined; get_config(unique_id: number): object; get_css_id_by_unique_id(unique_id: number): number | undefined; get_data_by_key(unique_id: number, key: string): any; get_dataset(unique_id: number): object; - get_dom_by_unique_id(unique_id: number): HTMLElement | undefined; + get_dom_by_unique_id(unique_id: number): WeakRef | undefined; get_element_config(unique_id: number): object | undefined; get_event(unique_id: number, event_name: string, event_type: string): any; get_events(unique_id: number): EventInfo[]; @@ -201,9 +202,10 @@ export interface InitOutput { readonly mainthreadwasmcontext_add_dataset: (a: number, b: number, c: any, d: any) => [number, number]; readonly mainthreadwasmcontext_add_run_worklet_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; readonly mainthreadwasmcontext_common_event_handler: (a: number, b: any, c: number, d: number, e: number, f: number, g: number) => void; - readonly mainthreadwasmcontext_create_element_common: (a: number, b: number, c: any, d: number, e: number, f: number) => number; + readonly mainthreadwasmcontext_create_element_common: (a: number, b: number, c: any, d: any, e: number, f: number, g: number) => number; readonly mainthreadwasmcontext_dispatch_event_by_path: (a: number, b: number, c: number, d: number, e: number, f: number, g: any) => number; readonly mainthreadwasmcontext_dispatch_global_bind_event: (a: number, b: number, c: number, d: number, e: number, f: any) => void; + readonly mainthreadwasmcontext_gc: (a: number) => void; readonly mainthreadwasmcontext_get_component_id: (a: number, b: number) => [number, number, number, number]; readonly mainthreadwasmcontext_get_config: (a: number, b: number) => [number, number, number]; readonly mainthreadwasmcontext_get_css_id_by_unique_id: (a: number, b: number) => number; diff --git a/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts b/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts index 05b52af61f..350a3ae89a 100644 --- a/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts +++ b/packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts @@ -23,9 +23,10 @@ export const mainthreadwasmcontext_add_cross_thread_event: (a: number, b: number export const mainthreadwasmcontext_add_dataset: (a: number, b: number, c: any, d: any) => [number, number]; export const mainthreadwasmcontext_add_run_worklet_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; export const mainthreadwasmcontext_common_event_handler: (a: number, b: any, c: number, d: number, e: number, f: number, g: number) => void; -export const mainthreadwasmcontext_create_element_common: (a: number, b: number, c: any, d: number, e: number, f: number) => number; +export const mainthreadwasmcontext_create_element_common: (a: number, b: number, c: any, d: any, e: number, f: number, g: number) => number; export const mainthreadwasmcontext_dispatch_event_by_path: (a: number, b: number, c: number, d: number, e: number, f: number, g: any) => number; export const mainthreadwasmcontext_dispatch_global_bind_event: (a: number, b: number, c: number, d: number, e: number, f: any) => void; +export const mainthreadwasmcontext_gc: (a: number) => void; export const mainthreadwasmcontext_get_component_id: (a: number, b: number) => [number, number, number, number]; export const mainthreadwasmcontext_get_config: (a: number, b: number) => [number, number, number]; export const mainthreadwasmcontext_get_css_id_by_unique_id: (a: number, b: number) => number; diff --git a/packages/web-platform/web-core/binary/client_legacy/client.d.ts b/packages/web-platform/web-core/binary/client_legacy/client.d.ts index 942ed1e0dc..7fbe9cbda5 100644 --- a/packages/web-platform/web-core/binary/client_legacy/client.d.ts +++ b/packages/web-platform/web-core/binary/client_legacy/client.d.ts @@ -22,15 +22,16 @@ export class MainThreadWasmContext { add_dataset(unique_id: number, key: any, value: any): void; add_run_worklet_event(unique_id: number, event_type: string, event_name: string, event_handler_identifier?: any | null): void; common_event_handler(event: any, bubble_unique_id_path: Uint32Array, event_name: string, is_bubble: boolean): void; - create_element_common(parent_component_unique_id: number, dom: HTMLElement, css_id?: number | null, component_id?: string | null): number; + create_element_common(parent_component_unique_id: number, dom: HTMLElement, dom_ref: WeakRef, css_id?: number | null, component_id?: string | null): number; dispatch_event_by_path(bubble_unique_id_path: Uint32Array, event_name: string, is_capture: boolean, serialized_event: any): boolean; dispatch_global_bind_event(bubble_unique_id_path: Uint32Array, event_name: string, serialized_event: any): void; + gc(): void; get_component_id(unique_id: number): string | undefined; get_config(unique_id: number): object; get_css_id_by_unique_id(unique_id: number): number | undefined; get_data_by_key(unique_id: number, key: string): any; get_dataset(unique_id: number): object; - get_dom_by_unique_id(unique_id: number): HTMLElement | undefined; + get_dom_by_unique_id(unique_id: number): WeakRef | undefined; get_element_config(unique_id: number): object | undefined; get_event(unique_id: number, event_name: string, event_type: string): any; get_events(unique_id: number): EventInfo[]; @@ -201,9 +202,10 @@ export interface InitOutput { readonly mainthreadwasmcontext_add_dataset: (a: number, b: number, c: number, d: number, e: number) => void; readonly mainthreadwasmcontext_add_run_worklet_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; readonly mainthreadwasmcontext_common_event_handler: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; - readonly mainthreadwasmcontext_create_element_common: (a: number, b: number, c: number, d: number, e: number, f: number) => number; + readonly mainthreadwasmcontext_create_element_common: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number; readonly mainthreadwasmcontext_dispatch_event_by_path: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number; readonly mainthreadwasmcontext_dispatch_global_bind_event: (a: number, b: number, c: number, d: number, e: number, f: number) => void; + readonly mainthreadwasmcontext_gc: (a: number) => void; readonly mainthreadwasmcontext_get_component_id: (a: number, b: number, c: number) => void; readonly mainthreadwasmcontext_get_config: (a: number, b: number, c: number) => void; readonly mainthreadwasmcontext_get_css_id_by_unique_id: (a: number, b: number) => number; diff --git a/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts b/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts index 052e560b78..89bf0a44ab 100644 --- a/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts +++ b/packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts @@ -23,9 +23,10 @@ export const mainthreadwasmcontext_add_cross_thread_event: (a: number, b: number export const mainthreadwasmcontext_add_dataset: (a: number, b: number, c: number, d: number, e: number) => void; export const mainthreadwasmcontext_add_run_worklet_event: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; export const mainthreadwasmcontext_common_event_handler: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; -export const mainthreadwasmcontext_create_element_common: (a: number, b: number, c: number, d: number, e: number, f: number) => number; +export const mainthreadwasmcontext_create_element_common: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number; export const mainthreadwasmcontext_dispatch_event_by_path: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number; export const mainthreadwasmcontext_dispatch_global_bind_event: (a: number, b: number, c: number, d: number, e: number, f: number) => void; +export const mainthreadwasmcontext_gc: (a: number) => void; export const mainthreadwasmcontext_get_component_id: (a: number, b: number, c: number) => void; export const mainthreadwasmcontext_get_config: (a: number, b: number, c: number) => void; export const mainthreadwasmcontext_get_css_id_by_unique_id: (a: number, b: number) => number; diff --git a/packages/web-platform/web-core/src/js_binding/mts_js_binding.rs b/packages/web-platform/web-core/src/js_binding/mts_js_binding.rs index 9bfdb2eb2e..ba9f93a853 100644 --- a/packages/web-platform/web-core/src/js_binding/mts_js_binding.rs +++ b/packages/web-platform/web-core/src/js_binding/mts_js_binding.rs @@ -36,24 +36,39 @@ extern "C" { #[wasm_bindgen(method, js_name = "addEventListener")] pub fn add_event_listener(this: &RustMainthreadContextBinding, event_name: &str); - #[wasm_bindgen(method, js_name = "enableElementEvent")] + #[wasm_bindgen(method, catch, js_name = "enableElementEvent")] pub fn enable_element_event( this: &RustMainthreadContextBinding, - element: &web_sys::HtmlElement, + element: &js_sys::WeakRef, event_name: &str, - ); + ) -> Result<(), JsValue>; - #[wasm_bindgen(method, js_name = "disableElementEvent")] + #[wasm_bindgen(method, catch, js_name = "disableElementEvent")] pub fn disable_element_event( this: &RustMainthreadContextBinding, - element: &web_sys::HtmlElement, + element: &js_sys::WeakRef, event_name: &str, - ); + ) -> Result<(), JsValue>; - #[wasm_bindgen(method, js_name = "getClassList")] + #[wasm_bindgen(method, catch, js_name = "getClassList")] pub fn get_class_name_list( this: &RustMainthreadContextBinding, - element: &web_sys::HtmlElement, - ) -> Vec; + element: &js_sys::WeakRef, + ) -> Result, JsValue>; + + #[wasm_bindgen(method, catch, js_name = "setAttribute")] + pub fn set_attribute( + this: &RustMainthreadContextBinding, + element: &js_sys::WeakRef, + name: &str, + value: &str, + ) -> Result<(), JsValue>; + + #[wasm_bindgen(method, catch, js_name = "removeAttribute")] + pub fn remove_attribute( + this: &RustMainthreadContextBinding, + element: &js_sys::WeakRef, + name: &str, + ) -> Result<(), JsValue>; } diff --git a/packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs b/packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs index b05c571e61..06415fa99c 100644 --- a/packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs +++ b/packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs @@ -66,13 +66,13 @@ impl MainThreadWasmContext { if should_enable { if let Some(element) = self.unique_id_to_dom_map.get(&unique_id) { - self + let _ = self .mts_binding .enable_element_event(element, event_name_str); } } else if should_disable { if let Some(element) = self.unique_id_to_dom_map.get(&unique_id) { - self + let _ = self .mts_binding .disable_element_event(element, event_name_str); } @@ -122,13 +122,13 @@ impl MainThreadWasmContext { if should_enable { if let Some(element) = self.unique_id_to_dom_map.get(&unique_id) { - self + let _ = self .mts_binding .enable_element_event(element, event_name_str); } } else if should_disable { if let Some(element) = self.unique_id_to_dom_map.get(&unique_id) { - self + let _ = self .mts_binding .disable_element_event(element, event_name_str); } diff --git a/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs b/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs index 0f4246813d..34bf3795a9 100644 --- a/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs +++ b/packages/web-platform/web-core/src/main_thread/client/element_apis/style_apis.rs @@ -23,12 +23,22 @@ impl MainThreadWasmContext { { let element = self.unique_id_to_dom_map.get(&unique_id).expect_throw("El"); if let Some(entry_name) = &entry_name { - let _ = element.set_attribute(constants::LYNX_ENTRY_NAME_ATTRIBUTE, entry_name); + let _ = self.mts_binding.set_attribute( + element, + constants::LYNX_ENTRY_NAME_ATTRIBUTE, + entry_name, + ); } if css_id != 0 { - let _ = element.set_attribute(constants::CSS_ID_ATTRIBUTE, &css_id.to_string()); + let _ = self.mts_binding.set_attribute( + element, + constants::CSS_ID_ATTRIBUTE, + &css_id.to_string(), + ); } else { - let _ = element.remove_attribute(constants::CSS_ID_ATTRIBUTE); + let _ = self + .mts_binding + .remove_attribute(element, constants::CSS_ID_ATTRIBUTE); } { let element_data_cell = self.get_element_data_by_unique_id(unique_id).unwrap_throw(); @@ -54,7 +64,10 @@ impl MainThreadWasmContext { self.style_manager.update_css_og_style( unique_id, element_data.css_id, - self.mts_binding.get_class_name_list(element), + self + .mts_binding + .get_class_name_list(element) + .unwrap_or_default(), entry_name, )?; Ok(()) diff --git a/packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs b/packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs index d67f7e8c03..7b07b6ad28 100644 --- a/packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs +++ b/packages/web-platform/web-core/src/main_thread/client/main_thread_context.rs @@ -17,7 +17,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] pub struct MainThreadWasmContext { pub(super) unique_id_to_element_map: Vec>>>>, - pub(super) unique_id_to_dom_map: FnvHashMap, + pub(super) unique_id_to_dom_map: FnvHashMap, pub(super) timing_flags: Vec, pub(super) enabled_events: FnvHashSet, @@ -78,6 +78,7 @@ impl MainThreadWasmContext { self: &mut MainThreadWasmContext, parent_component_unique_id: usize, dom: web_sys::HtmlElement, + dom_ref: js_sys::WeakRef, css_id: Option, component_id: Option, ) -> usize { @@ -111,11 +112,11 @@ impl MainThreadWasmContext { self .unique_id_to_element_map .push(Some(Rc::new(RefCell::new(element_data)))); - self.unique_id_to_dom_map.insert(unique_id, dom.clone()); + self.unique_id_to_dom_map.insert(unique_id, dom_ref); unique_id } - pub fn get_dom_by_unique_id(&self, unique_id: usize) -> Option { + pub fn get_dom_by_unique_id(&self, unique_id: usize) -> Option { self.unique_id_to_dom_map.get(&unique_id).cloned() } @@ -145,10 +146,18 @@ impl MainThreadWasmContext { .map(|element_data_cell| element_data_cell.borrow().css_id) } - // pub fn gc(&mut self) { - // self.unique_id_to_element_map.retain(|_, value| { - // let dom = value.get_dom(); - // dom.is_connected() - // }); - // } + pub fn gc(&mut self) { + let mut ids_to_remove = Vec::new(); + for (unique_id, weak_ref) in self.unique_id_to_dom_map.iter() { + if weak_ref.deref().is_none() { + ids_to_remove.push(*unique_id); + } + } + for id in ids_to_remove { + self.unique_id_to_dom_map.remove(&id); + if let Some(element_data) = self.unique_id_to_element_map.get_mut(id) { + *element_data = None; + } + } + } } diff --git a/packages/web-platform/web-core/tests/element-apis.spec.ts b/packages/web-platform/web-core/tests/element-apis.spec.ts index 2797e3fb26..ebcea8431d 100644 --- a/packages/web-platform/web-core/tests/element-apis.spec.ts +++ b/packages/web-platform/web-core/tests/element-apis.spec.ts @@ -1576,9 +1576,9 @@ describe('Element APIs', () => { mtsGlobalThis.__AppendElement(root, element); const spy = vi.spyOn(mtsBinding, 'getClassList'); - const classes = mtsBinding.getClassList(element); + const classes = mtsBinding.getClassList(new WeakRef(element)); - expect(spy).toHaveBeenCalledWith(element); + expect(spy).toHaveBeenCalledWith(expect.any(WeakRef)); expect(classes).toEqual(expect.arrayContaining(['foo', 'bar'])); expect(classes.length).toBe(2); }); diff --git a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts index 539b67d46e..b8674f1822 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts @@ -60,13 +60,17 @@ export class WASMJSBinding implements RustMainthreadContextBinding { } getClassList( - element: HTMLElement, + elementRef: WeakRef, ): string[] { - return [...(element.classList as unknown as string[])]; + const element = elementRef.deref(); + if (element) { + return [...(element.classList as unknown as string[])]; + } + return []; } getElementByUniqueId(uniqueId: number): HTMLElement | undefined { - return this.wasmContext?.get_dom_by_unique_id(uniqueId); + return this.wasmContext?.get_dom_by_unique_id(uniqueId)?.deref(); } getElementByComponentId( @@ -203,17 +207,33 @@ export class WASMJSBinding implements RustMainthreadContextBinding { ); } - enableElementEvent(element: HTMLElement, eventName: string) { + enableElementEvent(elementRef: WeakRef, eventName: string) { + const element = elementRef.deref(); if (element) { // @ts-expect-error element.enableEvent?.(LynxEventNameToW3cCommon[eventName] ?? eventName); } } - disableElementEvent(element: HTMLElement, eventName: string) { + disableElementEvent(elementRef: WeakRef, eventName: string) { + const element = elementRef.deref(); if (element) { // @ts-expect-error element.disableEvent?.(LynxEventNameToW3cCommon[eventName] ?? eventName); } } + + setAttribute(elementRef: WeakRef, name: string, value: string) { + const element = elementRef.deref(); + if (element) { + element.setAttribute(name, value); + } + } + + removeAttribute(elementRef: WeakRef, name: string) { + const element = elementRef.deref(); + if (element) { + element.removeAttribute(name); + } + } } diff --git a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts index 27ab251815..c926280047 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts @@ -140,6 +140,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, @@ -148,6 +149,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, @@ -156,13 +158,18 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, __CreateRawText(text) { const dom = document.createElement('raw-text') as DecoratedHTMLElement; dom.setAttribute('text', text); - dom[uniqueIdSymbol] = wasmContext.create_element_common(-1, dom); + dom[uniqueIdSymbol] = wasmContext.create_element_common( + -1, + dom, + new WeakRef(dom), + ); return dom; }, __CreateScrollView(parentComponentUniqueId) { @@ -171,6 +178,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, @@ -181,6 +189,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, @@ -195,6 +204,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), cssID, componentID, ); @@ -213,6 +223,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, @@ -223,6 +234,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( parentComponentUniqueId, dom, + new WeakRef(dom), ); return dom; }, @@ -234,6 +246,7 @@ export function createElementAPI( dom[uniqueIdSymbol] = wasmContext.create_element_common( 0, dom, + new WeakRef(dom), cssID, componentID, ); @@ -591,6 +604,7 @@ export function createElementAPI( timingFlagsAll, pipelineId, ); + wasmContext.gc(); }); timingFlags.length = 0; const enabledExposureElements = [ diff --git a/packages/web-platform/web-core/ts/types/IMtsBinding.ts b/packages/web-platform/web-core/ts/types/IMtsBinding.ts index 3dbac570bf..8ff09c5370 100644 --- a/packages/web-platform/web-core/ts/types/IMtsBinding.ts +++ b/packages/web-platform/web-core/ts/types/IMtsBinding.ts @@ -37,9 +37,17 @@ export interface RustMainthreadContextBinding { toEnable: boolean, ): void; - enableElementEvent(element: HTMLElement, eventName: string): void; + enableElementEvent(element: WeakRef, eventName: string): void; - disableElementEvent(element: HTMLElement, eventName: string): void; + disableElementEvent(element: WeakRef, eventName: string): void; - getClassList(element: HTMLElement): string[]; + getClassList(element: WeakRef): string[]; + + setAttribute( + element: WeakRef, + name: string, + value: string, + ): void; + + removeAttribute(element: WeakRef, name: string): void; } From 4c786051466f97a6466d07407b33ae2e0351bb9b Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:19:12 +0800 Subject: [PATCH 2/3] fix: cast WASM element lookup to HTMLElement to ensure correct return type --- .../ts/client/mainthread/elementAPIs/WASMJSBinding.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts index b8674f1822..2d169e5cbd 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts @@ -70,7 +70,9 @@ export class WASMJSBinding implements RustMainthreadContextBinding { } getElementByUniqueId(uniqueId: number): HTMLElement | undefined { - return this.wasmContext?.get_dom_by_unique_id(uniqueId)?.deref(); + return this.wasmContext?.get_dom_by_unique_id(uniqueId)?.deref() as + | HTMLElement + | undefined; } getElementByComponentId( From 965bd1f096c93465ca7daf13a3f73d9cfa7b7e0d Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:21:51 +0800 Subject: [PATCH 3/3] + fix --- .../ts/client/mainthread/elementAPIs/createElementAPI.ts | 7 +++++-- packages/web-platform/web-core/ts/client/wasm.ts | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts index c926280047..a5b3bc549f 100644 --- a/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts +++ b/packages/web-platform/web-core/ts/client/mainthread/elementAPIs/createElementAPI.ts @@ -125,7 +125,9 @@ export function createElementAPI( ); } if (eventName === 'uiappear' || eventName === 'uidisappear') { - const element = wasmContext.get_dom_by_unique_id(uniqueId); + const element = wasmContext.get_dom_by_unique_id(uniqueId)?.deref() as + | HTMLElement + | undefined; if (element) { mtsBinding.markExposureRelatedElementByUniqueId( element, @@ -433,7 +435,8 @@ export function createElementAPI( false, ) as number | undefined; if (typeof childSign === 'number') { - const childElement = wasmContext.get_dom_by_unique_id(childSign); + const childElement = wasmContext.get_dom_by_unique_id(childSign) + ?.deref() as HTMLElement | undefined; if (childElement) { const referenceNode = element.children[action.position]; if (referenceNode !== childElement) { diff --git a/packages/web-platform/web-core/ts/client/wasm.ts b/packages/web-platform/web-core/ts/client/wasm.ts index 0bcd857ad7..b7a189df57 100644 --- a/packages/web-platform/web-core/ts/client/wasm.ts +++ b/packages/web-platform/web-core/ts/client/wasm.ts @@ -4,6 +4,7 @@ * LICENSE file in the root directory of this source tree. */ import { referenceTypes, simd } from 'wasm-feature-detect'; +import type * as WasmInstanceType from '../../binary/client/client.js'; const isWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; const wasmLoaded = Promise.all([referenceTypes(), simd()]).then( @@ -57,7 +58,7 @@ const wasmLoaded = Promise.all([referenceTypes(), simd()]).then( ]); } }, -); +) as Promise<[typeof WasmInstanceType, WebAssembly.Module]>; export const [wasmInstance, wasmModule] = await wasmLoaded; if (!isWorker) { wasmInstance.initSync({ module: wasmModule! });