Notices
-
Threading support now requires
-Clink-arg=--export=__heap_baseto be set inRUSTFLAGSfor nightly toolchains from 2026-05-06 onward, after [rust-lang/rust#156174](https://github.com/rust-lang/rust/issues/156174) removed the implicit__heap_base/__data_endexports onwasm*targets. Atomics CI, CLI reference tests, and thenodejs-threads,raytrace-parallel, andwasm-audio-workletexamples have been updated to pass--export=__heap_baseexplicitly. The flag is backward-compatible with older nightlies. -
-Cpanic=unwindon wasm targets now emits modern (exnref) exception handling by default after [rust-lang/rust#156061](https://github.com/rust-lang/rust/issues/156061), and requires Node.js 22.22.3+ (forWebAssembly.JSTag). Legacy EH wasm can still be produced on current nightlies by adding-Cllvm-args=-wasm-use-legacy-ehtoRUSTFLAGS; Node.js 20 may be supported with legacy exception handling, with a tracking issue in #5151.
Added
-
Implemented
TryFromJsValueforVec<T>whereT: TryFromJsValue. A JS value converts when it is a realArray(perArray.isArray) and every element converts viaT::try_from_js_value. This composes recursively (Vec<Vec<String>>,Vec<Option<T>>) and works for anyTwith aTryFromJsValueimpl, including primitives,String,JsValue, andJsCasttypes. Array-likes (objects withlengthand numeric indices) are intentionally rejected to mirror the static ABI representation used byjs_value_vector_from_abi. -
New
extends_js_classandextends_js_namespaceattributes on exported structs to allow defining the parentjs_classname when it has been customized byjs_nameand the parent's ownjs_namespaceas well in turn. New validation is added at code generation time that will now catch these cases instead of emitting invalid code. Example:
```rust #[wasm_bindgen(js_name = "Animal", js_namespace = zoo)] pub struct AnimalImpl { / ... / }
#[wasm_bindgen( extends = AnimalImpl, extends_js_class = "Animal", extends_js_namespace = zoo, )] pub struct DogImpl { / ... / } ``` #5154
Changed
- When an exported struct uses
js_namespace, the corresponding value must now be repeated on everyimplblock. Previously the impl-side defaults silently worked resulting in inconsistent emission. Example:
```rust // Before: #[wasm_bindgen(js_namespace = "default")] pub struct Counter { / ... / }
#[wasm_bindgen] // worked, but fragile impl Counter { / ... / }
// After: #[wasm_bindgen(js_namespace = "default")] pub struct Counter { / ... / }
#[wasm_bindgen(js_namespace = "default")] // now required
impl Counter { / ... / }
``
To ease this transition forjs_namespace` usage, diagnostic
messages now include hints for missing namespaces for easier
fixing.
Fixed
-
Fixed the descriptor interpreter panicking on
BrandBrIfinstructions emitted by recent nightly compilers when building withpanic=unwind. #5158 -
Emscripten output now works against vanilla upstream emscripten without requiring a fork. Dependency tracking,
HEAP_DATA_VIEWsetup, function-decl intrinsic inlining, catch-wrapper gating, and imported global handling have all been corrected; ESM imports (#[wasm_bindgen(module = "...")]and snippets) are emitted to a sidecarlibrary_bindgen.extern-pre.jsconsumers pass to emcc via--extern-pre-js; namespaced exports (js_namespace = [...]on a struct/impl) now attach toModule.<segments>instead of emitting top-levelexport const(which emcc's library evaluator rejects); the generated.d.tsfor namespaced exports is now valid TypeScript (mangled identifiers stay module-internal viadeclare class/declare enum/declare functionplusexport { BindgenModule };to mark the file as a module; no spurious unqualifiedCalc:property onBindgenModulefor namespaced items; namespace shapes land as plain interface members (app: { math: { Calc: typeof app__math__Calc } };) instead of the previously-emittedexport let app: { ... };which was invalid TS1131 syntax inside an interface body). #5156 -
Fixed a duplicate phantom class being emitted for an exported struct renamed via
js_name(Rust ident != JS class name) and/or placed in ajs_namespace, when the struct crosses the boundary as aJsValue(e.g. via.into()). TheWrapInExportedClass/UnwrapExportedClassimports were keyed by the Rust ident rather than the qualified JS name thatexported_classesis keyed by (a regression from [#5154]), so a fresh empty class entry was minted and emitted alongside the real one, with afree()referencing a nonexistent wasm export. Riding the same release's [#5154] wire-format bump, the now-vestigialrust_namefield is dropped from the schema and the namespace-qualified name is no longer cached onAuxStruct,AuxEnum, orExportedClass(derived on demand from(name, js_namespace)), collapsing three fallback chains that only papered over the pre-#5154 keying.