wasm-bindgen icon indicating copy to clipboard operation
wasm-bindgen copied to clipboard

Imports with `#[wasm_bindgen(js_name = default)]` from a local module with a default export break when compiling to a library

Open expenses opened this issue 3 years ago • 2 comments

Describe the Bug

I'm trying to bind with a local module like so:

#[wasm_bindgen(module = "/module.js")]
extern "C" {
    #[wasm_bindgen(js_name = default)]
    fn init() {
        ...    
    }
}

where module.js looks like this:

function init() {...}
export default init;

Unfortunately, the resulting generated js bindings file for the rust library has an import that looks like this:

import { _default } from './snippets/module.js';
...
export default init;

Because module.js has a default export, { _default } doesn't match with anything and is broken.

Expected Behavior

What should be happening is this:

import { default as _default } from './snippets/module.js';

I've written a small patch that fixes this issue:

diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs
index 247792239..09d2f4e35 100644
--- a/crates/cli-support/src/js/mod.rs
+++ b/crates/cli-support/src/js/mod.rs
@@ -2223,6 +2223,12 @@ impl<'a> Context<'a> {
     }
 
     fn add_module_import(&mut self, module: String, name: &str, actual: &str) {
+        let mut name = name.to_string();
+
+        if name == "_default" {
+            name = "default".to_string();
+        }
+
         let rename = if name == actual {
             None
         } else {

However this is probably the wrong way to handle this edgecase.

expenses avatar Jul 29 '22 15:07 expenses

In some different code I've written, a similar thing works fine:

import { default as default1 } from './snippets/basis-universal-wasm-8dd816e8505190b7/basis_universal/webgl/transcoder/build/basis_transcoder.js';

No clue what the difference between the two projects is.

expenses avatar Jul 29 '22 15:07 expenses

I seem to have encountered the same problem.

Rust source:

#[wasm_bindgen(raw_module ="/static/my_module.js")]
extern "C"{
    #[wasm_bindgen(js_name = "default")]
    async fn init(wasm_path: &str);
}

Generated binding: import { _default } from '/static/my_module.js';

Gearme avatar Aug 20 '22 22:08 Gearme

This issue is still present on HEAD (roughly v0.10.3 at the time of this writing). JavaScript code:

export default function sayName() {
    return 'name-mjs-default';
}

Rust binding:

#[wasm_bindgen(module = "name-mjs-default")]
extern "C" {
    #[wasm_bindgen(js_name = default)]
    fn say_name() -> JsValue;
}

The call site looks okay:

export function __wbg_default_a3453669932eede7() { return logError(function () {
    const ret = _default();
    return addHeapObject(ret);
}, arguments) };

But the import statement is wrong:

import { _default } from 'name-mjs-default';

I confirmed that it's wrong for both CommonJS and ES6 modules (in case that makes a difference).

AmateurECE avatar Oct 28 '22 15:10 AmateurECE