tmm1 / taxsim.js

JS/WebAssembly version of NBER TAXSIM
22 stars 2 forks source link

Google App Scripts support? #2

Closed mcolyer closed 2 years ago

mcolyer commented 2 years ago

So I've confirmed that Google App Scripts is V8 based and that it does support simple wasm, but when I try to import taxsim.js and execute it fails like so:

10:12:01 AM Warning Aborted(ReferenceError: read is not defined)

10:12:01 AM Warning failed to asynchronously prepare wasm: RuntimeError: Aborted(ReferenceError: read is not defined). Build with -s ASSERTIONS=1 for more info.

10:12:01 AM Warning Aborted(RuntimeError: Aborted(ReferenceError: read is not defined). Build with -s ASSERTIONS=1 for more info.)

10:12:01 AM Error   
RuntimeError: Aborted(ReferenceError: read is not defined). Build with -s ASSERTIONS=1 for more info.
abort   @ TaxSim.gs:1304
getBinary   @ TaxSim.gs:1355
(anonymous) @ TaxSim.gs:1380

I'm guessing that there needs to be a read implementation but I'm not exactly sure where to look next.

tmm1 commented 2 years ago

I think this happens when the js can't load the wasm file.

You can bundle it directly and pass it as wasmBinary as second argument. See for example how the R/v8 example works.

tmm1 commented 2 years ago

emscripten has two read implementations, one that uses nodejs fs APIs and another that uses XHR:

$ curl -s https://taxsim.app/taxsim.js | grep -C5 "read_ ="
    fs = require('fs');
    nodePath = require('path');
  }
};

read_ = function shell_read(filename, binary) {
  requireNodeFS();
  filename = nodePath['normalize'](filename);
  return fs.readFileSync(filename, binary ? null : 'utf8');
};

--

} else
if (ENVIRONMENT_IS_SHELL) {

  if (typeof read != 'undefined') {
    read_ = function shell_read(f) {
      return read(f);
    };
  }

  readBinary = function readBinary(f) {
--
  // be done differently.
  {
// include: web_or_worker_shell_read.js

  read_ = (url) => {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url, false);
      xhr.send(null);
      return xhr.responseText;
  }

Since neither of these are available in the appscript environment, it's erroring out.

If XHR is actually available, then it could be the detection code is failing:

// Attempt to auto-detect the environment
var ENVIRONMENT_IS_WEB = typeof window === 'object';
var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
// N.b. Electron.js environment is simultaneously a NODE-environment, but
// also a web environment.
var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
tmm1 commented 2 years ago

You can bundle it directly and pass it as wasmBinary as second argument. See for example how the R/v8 example works.

Basically instead of:

await taxsim({year:2020, mstat:2})

you would use:

let wasmBinary = ... // load contents of taxsim.wasm in whatever way is available
await taxsim({year:2020, mstat:2}, {wasmBinary})
mcolyer commented 2 years ago

Wow it works! I had to base64 encode the file to save it and then use Utilities.base64Decode() to turn it into a blob but it actually works!