WebAssembly InstantiateStreaming Wrong MIME type

2020-06-16 01:54发布

问题:

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.

回答1:

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.



回答2:

there was some error; TypeError: "Response has unsupported MIME type" The Web server you are running does not understands/serves a MIME type application/wasm.

You can use a rust based http server, it knows about wasm MIME type.

Installation

Simply use curl

curl -SsL https://cdn.rawgit.com/thecoshman/http/master/install.sh | sh

and execute the downloaded script or you can explorer other ways to do the same at https://crates.io/crates/https.


Running

Please use the downloaded server to server your Web Application(index.html). e.g

cd ${YOUR_APPS_PATH}

http


回答3:

A snippet of code for a workaround has been published on the WebAssembly Git here. Unfortunately, this is a workaround, and this defeats the purpose of instantiateStreaming() which is told here to be "a lot more efficient", since the workaround needs an ArrayBuffer that instantiateStreaming() helps to avoid.