[Rust/WASM/webpack] How to bundle a rust/wasm app to be used client side for production?

FTR: This is half rant and half a serious request for help.

I've been trying to get the wasm-pack tutorial app to load client-side without using the webpack-dev-server. And I'm hitting a brick wall there: the webpack-dev-server works fine, but it works with default settings and getting a feel for what's necessary to get it into production is an exercise in frustration, and thusfar a fruitless one.

Specifically, all kinds of sources tell me that wasm modules need to be asynchronously loaded.
But that's exactly what I don't want, because:

  1. It's an ugly solution, because it tries to get me to split my project (which is part Rust and part JavaScript) into multiple parts (1 part for wasm, 1 part for everything else) which is just plain bonkers because those parts belong together (which is why they're part of the same project in the first place!)
  2. It's a really ugly solution (and yeah I get the perf rationale behind it, but it's more work than it should be, and ATM I don't give 2 flying farts about performance. First I need to get it working, then I'll see about the rest)
  3. It's does not necessarily fit nicely into the larger project I need to integrate this project into.

So what do I need? I think I need a webpack config that:

  1. actually works (all the loaders so far fail miserably in actually getting the job done. I've tried rust-wasm-loader, rust-native-wasm-loader and wasm-loader).
  2. Allows me to integrate the project into another, larger one that runs in the browser.

In case it matters: the larger project is based on AngularJS (yes, the v1 one. But if it does matter, I can't imagine that AngularJS is actually helpful here).

Can anyone help a fellow rustacean out?

As a minor semi-related question: Why are Javascript's import systems(!!) such a gigantic mess?

I'm not entirely sure I understand the problem, but have you considered using wasm-bindgen --no-modules? This works around having to use any kind of module system (such as webpack) thus makes it easier to integrate your code as part of a javascript application that doesn't use one.

I don't follow how wasm-bindgen helps here?
It's the packaging stage (i.e. as far as I can tell that's wasm-pack's domain and further) that;s giving me issues.

BTW, just tried it:

✘  ~/Development/accept/sbr-validate-npm   wasm ●  wasm-bindgen --browser --no-modules
Invalid arguments.

Usage:
    wasm-bindgen [options] <input>
    wasm-bindgen -h | --help
    wasm-bindgen -V | --version

The output is the same when I omit either of the flags.

Using wasm-bindgen directly is a lower-level solution that bypasses wasm-pack (which normally takes care of running that for you), which generates javascript source and a wasm file that can be used directly.

As an example of using it see: build.sh · master · mara / wasm-game-of-life · GitLab and www/index.html · master · mara / wasm-game-of-life · GitLab

Anyhow, I don't know if this solves your problem at all, but I mention it because the result works in the browser without any special server or server-side packaging tools.

If it's only loading the .wasm from the browser that fails: have you made sure that the content type that your web server returns for .wasm files is application/wasm? browsers tend to be fussy about this.

Thanks for the answer, I'll have a look at the links.

The top-level interface is provided by a JavaScript file, which in turn loads the .wasm file. So that doesn't really solve anything unfortunately. But it's also something I didn't know so it's a good tip nonetheless.

To be clear: that's always the case. There's (unfortunately) no way to have wasm at top level, it always needs a minimal launcher/binding from JS and HTML. The content type requirement holds however the loading is done.

By stripping out the JavaScript part I was able to use wasm-bindgen with the --no-modules flag. This seems to have moved progress forward somewhat, but now I get a different issue:

I'm trying to load an HTML file which has a script tag pointing to the top-level JS file without a server in between (which is a hassle to set up for testing and development).
The loading itself seems to go fine, and I apparently get access to a wasm_bindgen handle, which looks like a promise:
13%20

The problem is, I can't for the life of me get the actual WASM module loaded.
The promise seems to want a proper URI (including http or https) but even when I try that (including a simple Python server), I get CORS errors.
This shouldn't be this difficult should it?

EDIT:
I got what seems like a bit farther, but I still get issues:
I caved to the async nonsense, so I try to do this now (taken from here):

(async () => {
  const response = await fetch('http://localhost:9080/sbr_validate_npm_bg.wasm');
  console.log(response);
  const module = await WebAssembly.compileStreaming(response);
  const instance = await WebAssembly.instantiate(module, {});
//   const result = instance.exports.fibonacci(42);
//   console.log(result);
})();

Now I get an error I don't even understand:

I tried buiding alternately with
wasm-pack build and
cargo build --target wasm32-unknown-unknown --release && wasm-bindgen ./target/wasm32-unknown-unknown/release/sbr_validate_npm.wasm --no-typescript --browser --out-dir blah/

I thought wasm-pack and wasm-bindgen were supposed to solve dependency issues?

to import functions from rust to javascript you can use parcel instead of webpack and wasm-bindgen, it is easier, see more:

https://en.parceljs.org/rust.html

1 Like

The idea here is great (no-config, no-fuss bundling? yes please!), but in practice it doesn't work for me. At all.
See here and here for more details.

@jjpe something that they has to fix (right that i didn't try before) but you should write the issue here Issues · parcel-bundler/parcel · GitHub instead of the website repository, it is about the website not about the parcel itself.

@jjpe such I told you, look in his answer. Please write here this way they can start to work on the issue.