How to embed wasm (WebAssembly) directly into a html file efficiently? typed array

3.2k views Asked by At

I need to embed a wasm app directly into the html page itself as opposed to load it (e.g. via xhr) from a separate file. So far I managed to embed it by "printing" the bytes straight into a Uint8Array (see below) but it's not space efficient(obviously). A 65MB wasm file becomes an 220 MB js file.

const go = new Go() WebAssembly.instantiate(new Uint8Array([0,97,115,109,1,0,0,0,0,242,128,128,128,0,10,103,111,46,98,117,105,108,100,105,100,255,32,71,111,32,98,117,105,108,100,32,73,68,58,32,34,56,69,84,87,98,97,65,117,88,67,100,52,98,55,72,90,112,90,114,70,47,85,111,66,116,82,89,102,80,118,83,101,111,69,111,106,117,50,85,99,90,47,115,77,71,110,85,106,....], { type: 'application/wasm' });

1

There are 1 answers

1
ColinE On

An efficient way to encode a WebAssembly module is using Base64 encoding. You can encode (in Node) as follows:

const readFileSync = require('fs').readFileSync;

const wasmCode = readFileSync(id);
const encoded = Buffer.from(wasmCode, 'binary').toString('base64')

And decode in a browser or Node as follows:

var encoded = "...";

function asciiToBinary(str) {
  if (typeof atob === 'function') {
    return atob(str)
  } else {
    return new Buffer(str, 'base64').toString('binary');
  }
}

function decode(encoded) {
  var binaryString =  asciiToBinary(encoded);
  var bytes = new Uint8Array(binaryString.length);
  for (var i = 0; i < binaryString.length; i++) {
    bytes[i] = binaryString.charCodeAt(i);
  }
  return bytes.buffer;
}

var instance = WebAssembly.instantiate(decode(encoded), importObject)
      .then(r => r.instance);