Skip to content

Unable to load wasm in electron. #11671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bcleveland1022 opened this issue Jul 17, 2020 · 8 comments · Fixed by #12921
Closed

Unable to load wasm in electron. #11671

bcleveland1022 opened this issue Jul 17, 2020 · 8 comments · Fixed by #12921

Comments

@bcleveland1022
Copy link

bcleveland1022 commented Jul 17, 2020

I was trying to run my app in electron and got the below warnings and errors during start up. The Strata-wasm.js is the javascript file generated by the em++ build using emscripten 1.39.19.

Strata-wasm.js:2212 failed to asynchronously prepare wasm: RuntimeError: abort(both async and sync fetching of the wasm failed) at Error
at jsStackTrace (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:3124:17)
at stackTrace (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:3141:16)
at abort (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2064:44)
at getBinary (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2144:5)
at file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2166:13
at new Promise (<anonymous>)
at getBinaryPromise (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2165:10)
at instantiateArrayBuffer (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2209:12)
at instantiateAsync (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2238:14)
at createWasm (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2254:3)


Uncaught (in promise) RuntimeError: abort(RuntimeError: abort(both async and sync fetching of the wasm failed) at Error
at jsStackTrace (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:3124:17)
at stackTrace (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:3141:16)
at abort (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2064:44)
at getBinary (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2144:5)
at file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2166:13
at new Promise (<anonymous>)
at getBinaryPromise (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2165:10)
at instantiateArrayBuffer (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2209:12)
at instantiateAsync (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2238:14)
at createWasm (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2254:3)) at Error
at jsStackTrace (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:3124:17)
at stackTrace (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:3141:16)
at abort (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2064:44)
at file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2215:7
at abort (file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2070:9)
at file:///C:/Users/clevelandb/opensphere-yarn-workspace/workspace/opensphere/dist/opensphere/v1595010164/vendor/strata/Strata-wasm.js:2215:7

After some investigation I noticed it was failing due to the isFileURI check within the auto generated Strata-wasm.js file, because we were running in electron and the wasm file was a local file within the electron application.

function getBinaryPromise() {
   // If we don't have the binary yet, and have the Fetch api, use that;
  // in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, 
let's only use it on the Web
  if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function'
      // Let's not use fetch to get objects over file:// as it's most likely Cordova which doesn't support fetch for file://
      && !isFileURI(wasmBinaryFile)
      ) {
    return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) {
      if (!response['ok']) {
        throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
      }
      return response['arrayBuffer']();
    }).catch(function () {
      return getBinary();
    });
  }
  // Otherwise, getBinary should be able to get it synchronously
  return new Promise(function(resolve, reject) {
    resolve(getBinary());
  });
}

    // Prefer streaming instantiation if available.
  function instantiateAsync() {
    if (!wasmBinary &&
        typeof WebAssembly.instantiateStreaming === 'function' &&
        !isDataURI(wasmBinaryFile) &&
        // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously.
        !isFileURI(wasmBinaryFile) &&
        typeof fetch === 'function') {
      fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) {
        var result = WebAssembly.instantiateStreaming(response, info);
        return result.then(receiveInstantiatedSource, function(reason) {
            // We expect the most common failure cause to be a bad MIME type for the binary,
            // in which case falling back to ArrayBuffer instantiation should work.
            err('wasm streaming compile failed: ' + reason);
            err('falling back to ArrayBuffer instantiation');
            return instantiateArrayBuffer(receiveInstantiatedSource);
          });
      });
    } else {
      return instantiateArrayBuffer(receiveInstantiatedSource);
    }
  }
  // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
  // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel
  // to any other async startup actions they are performing.
  if (Module['instantiateWasm']) {
    try {
      var exports = Module['instantiateWasm'](info, receiveInstance);
      return exports;
    } catch(e) {
      err('Module.instantiateWasm callback failed with error: ' + e);
      return false;
    }
  }
instantiateAsync();
  return {}; // no exports yet; we'll fill them in later
}

Currently our workaround for this issue is to modify the isFileURI to always return false then everything works as expected in electron.

@kripken
Copy link
Member

kripken commented Jul 17, 2020

I think this may be what the "webview" environment is for. Building with -s ENVIRONMENT=webview should make it work.

src/settings.js suggests this has been tested on cordova, but I think it might be the same? If you can confirm that, we should update those docs.

@bcleveland1022
Copy link
Author

Building with -s ENVIRONMENT=webview caused this to be thrown environment detection error when trying to load the wasm in electron.

@kripken
Copy link
Member

kripken commented Jul 20, 2020

Ok, then we need to debug why that error is thrown. Some logging around that statement should help. (I don't have an electron environment handy myself.)

@bcleveland1022
Copy link
Author

Looking at the javascript file generated by em++ the error is thrown from the block of code below and is thrown when we call the factory function.

// Note that this includes Node.js workers when relevant (pthreads is enabled).
// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
// ENVIRONMENT_IS_NODE.
{
  throw new Error('environment detection error');
}

@kripken
Copy link
Member

kripken commented Jul 23, 2020

That means the lines right above it all failed. So it did not recognize this environment as any of the ones it knows. It should probably detect it as ENVIRONMENT_IS_WEB, so finding out why that failed would help.

@bcleveland1022
Copy link
Author

Building with -s ENVIRONMENT=webview gives me the generated javascript code below to determine the environment. It doesn't look like there is any logic to determine the environment which then causes the environment detection error to be thrown.

// Determine the runtime environment we are in. You can customize this by
// setting the ENVIRONMENT setting at compile time (see settings.js).

var ENVIRONMENT_IS_WEB = false;
var ENVIRONMENT_IS_WORKER = false;
var ENVIRONMENT_IS_NODE = false;
var ENVIRONMENT_IS_SHELL = false;

if (Module['ENVIRONMENT']) {
  throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile- 
 time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)');
}



// `/` should be present at the end if `scriptDirectory` is not empty
var scriptDirectory = '';
function locateFile(path) {
  if (Module['locateFile']) {
    return Module['locateFile'](path, scriptDirectory);
  }
  return scriptDirectory + path;
}

// Hooks that are implemented differently in different runtime environments.
var read_,
    readAsync,
    readBinary,
    setWindowTitle;


// Note that this includes Node.js workers when relevant (pthreads is enabled).
// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
// ENVIRONMENT_IS_NODE.
{
  throw new Error('environment detection error');
}

Now when I build with -s ENVIRONMENT=web my wasm will load in both emscripten and a web browser. This works for me but I wanted to bring up the generated webview code in case this was an issue that still needs to be fixed.

@kripken
Copy link
Member

kripken commented Jul 28, 2020

I see the docs in settings.js say

//  * The webview target is basically a subset of web. It must be specified
//    alongside web (e.g. "web,webview") and we only use it for code generation
//    at compile time, there is no runtime behavior change.

So -s ENVIRONMENT=web,webview may be needed.

@bcleveland1022
Copy link
Author

Building with -s ENVIRONMENT=web,webview produced similar to code that I originally posted where it checks to see if the wasm uri is a file uri and since it is, it fails to load.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants