5

I'm trying to use the Web3 JavaScript library from Rust and I'm stuck. The standard usage of the library starts with:

// In Node.js use: const Web3 = require('web3');

let web3 = new Web3(Web3.givenProvider || "ws://localhost:8545");

The module you're supposed to import is a constructor, that also has some other properties. My Rust code that's supposed to bind this API looks like this:

#[wasm_bindgen(module = "web3")]
extern "C" {
    type Web3;

    #[wasm_bindgen(constructor)]
    fn new(_: &Provider) -> Web3;

    type Provider;

    static givenProvider: Provider;
}

Which ends up outputting import { Web3, givenProvider } from 'web3'; and trying to run new Web3(...) which fails. It should be doing something like import * as Web3 from 'web3';, running new Web3(...) and referencing Web3.givenProvider.

How can I get wasm-bindgen to output code like that?

Echo Nolan
  • 1,111
  • 1
  • 11
  • 23

1 Answers1

3

EDIT: The original answer is wrong. You can import things defined like that using wasm-bindgen, and they are legal ES6. Or at least the same concept is available in ES6 modules. They call them default exports/imports. It's a bit awkward, but the way to import them is to use js_name = "default". Like so:

#[wasm_bindgen(module = "web3")]
extern "C" {
    #[wasm_bindgen(js_name = "default")]
    type Web3;

    #[wasm_bindgen(constructor, js_class = "default")]
    fn new(_: &Provider) -> Web3;

    #[wasm_bindgen(static_method_of = Web3, getter, js_class = "default")]
    fn givenProvider() -> Provider;

    type Provider;
}

You need the js_class parameter on methods, it doesn't remember that Web3's js_name is default.


Old, wrong answer:

The reason you can't get wasm-bindgen to generate code like that is because it's not legal ES6. ECMAScript modules use named exports for everything. Web3 is actually a CommonJS module, and those do support having a single anonymous export.

The reason it almost works is because I was using webpack, and webpack lets you import CommonJS modules using ES6 syntax, even though the semantics are slightly different.

The solution is to make a little shim, exporting the CommonJS module from an ES6 module:

export let Web3 = require('web3');

Then this binding will work:

#[wasm_bindgen(module = "/src/web3-wrapper.js")]
extern "C" {
    type Web3;

    #[wasm_bindgen(constructor)]
    fn new(_: &Provider) -> Web3;

    #[wasm_bindgen(static_method_of = Web3, getter)]
    fn givenProvider() -> Provider;

    type Provider;
}
Echo Nolan
  • 1,111
  • 1
  • 11
  • 23