WebAssembly InstantiateStreaming Wrong MIME type

Peter Weyand picture Peter Weyand · Sep 9, 2018 · Viewed 9.6k times · Source

I am attempting to get this tutorial (here: https://www.hellorust.com/demos/add/index.html) to work, and it seems that whatever I do, I cannot get the WebAssembly MDN reserved function to properly work.

So, I followed the instructions on the link above and got an add.wasm file. As far as I can tell this should be fairly simple and should work. After a little digging I found that the newest WebAssembly module is to instantiate streaming - the documentation for which can be found here: (https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API).

The MDN example says to do the following:

var importObject = {
  imports: { imported_func: arg => console.log(arg) }
};

then

WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject)
.then(obj => obj.instance.exports.exported_func());

According to MDN the importObject is to unwrap the nested argument. Weird, but OK.

To make this as simple as possible I put the add.wasm file and the js file that would import it in the same directory and then did then following (NOTE: I am using Vue.js, but for anyone familiar with SPA like libraries this should be similar):

window.WebAssembly.instantiateStreaming(fetch('./add.wasm', {
  headers: {
    "Content-Type": "application/wasm",
  },
}), importObject)
.then(obj => {
  console.log('inside return obj from WebAssembly initiateStreaming')
  obj => obj.instance.exports.exported_func() 
})
.catch(error=>{
  console.log('there was some error; ', error)
});

The error I get back is:

there was some error;  TypeError: "Response has unsupported MIME type"

I've tried not adding the header to the fetch request, using fetch(add.wasm), dropping the window., dropping the importObject entirely and simple logging obj to console. Nothing appears to work.

It may be that I have to add the application/wasm field to webpack somehow if it is not widely supported, but I'm not sure and I haven't seen any examples online.

Does anyone know how to get this to work?

EDIT:

Someone suggested that since this was a fetch request it had to be making the request from a backend server. This made sense to me, so I did the following:

    WebAssembly.instantiateStreaming(fetch('http://localhost:8000/files/add.wasm'), importObject)
    .then(obj => {
      console.log('inside return obj from WebAssembly initiateStreaming')
      obj => obj.instance.exports.exported_func()
    })
    .catch(error=>{
      console.log('there was some error; ', error)
    });

Where http://localhost:8000/files/{someFile} is a backend route that serves my files (which I made sure to put add.wasm in of course). Unfortunately, I get the same error (i.e. unrecognized MIME type) and I'm not sure why.

Answer

Lucio Paiva picture Lucio Paiva · Oct 10, 2018

Considering you can't change the server to properly return application/wasm for .wasm file requests for any reason, you can work around the issue by changing the way you instantiate the WebAssembly module. Instead of doing this:

WebAssembly.instantiateStreaming(fetch("./add.wasm")).then(obj => /* ... */)

Do this:

const response = await fetch("add.wasm");
const buffer = await response.arrayBuffer();
const obj = await WebAssembly.instantiate(buffer);
obj.instance.exports.exported_func();

Or the equivalent using then() if you cannot use async/await.

In practice, what my workaround does is to avoid calling instantiateStreaming(), which must check the MIME type returned by the server before proceeding (according to this specification). Instead, I call instantiate() passing an ArrayBuffer and avoid the check altogether.