JS Bindings
wasm-bindgen
should look something like this.
bincode_parser.js
/* tslint:disable */
import * as wasm from './bincode_parser_bg';
const __wbg_f_log_log_n_target = console.log;
let cachedDecoder = new TextDecoder('utf-8');
let cachedUint8Memory = null;
function getUint8Memory() {
if (cachedUint8Memory === null ||
cachedUint8Memory.buffer !== wasm.memory.buffer)
cachedUint8Memory = new Uint8Array(wasm.memory.buffer);
return cachedUint8Memory;
}
function getStringFromWasm(ptr, len) {
return cachedDecoder.decode(getUint8Memory().slice(ptr, ptr + len));
}
let cachedUint32Memory = null;
function getUint32Memory() {
if (cachedUint32Memory === null ||
cachedUint32Memory.buffer !== wasm.memory.buffer)
cachedUint32Memory = new Uint32Array(wasm.memory.buffer);
return cachedUint32Memory;
}
let cachedGlobalArgumentPtr = null;
function globalArgumentPtr() {
if (cachedGlobalArgumentPtr === null)
cachedGlobalArgumentPtr = wasm.__wbindgen_global_argument_ptr();
return cachedGlobalArgumentPtr;
}
function getGlobalArgument(arg) {
const idx = globalArgumentPtr() / 4 + arg;
return getUint32Memory()[idx];
}
export function __wbg_f_log_log_n(arg0) {
let len0 = getGlobalArgument(0);
let v0 = getStringFromWasm(arg0, len0);
__wbg_f_log_log_n_target(v0);
}
function passArray8ToWasm(arg) {
const ptr = wasm.__wbindgen_malloc(arg.length);
getUint8Memory().set(arg, ptr);
return [ptr, arg.length];
}
function setGlobalArgument(arg, i) {
const idx = globalArgumentPtr() / 4 + i;
getUint32Memory()[idx] = arg;
}
export function bincode_to_json(arg0) {
const [ptr0, len0] = passArray8ToWasm(arg0);
setGlobalArgument(len0, 0);
const ret = wasm.bincode_to_json(ptr0);
const len = getGlobalArgument(0);
const realRet = getStringFromWasm(ret, len);
wasm.__wbindgen_free(ret, len * 1);
return realRet;
}
let cachedEncoder = new TextEncoder('utf-8');
function passStringToWasm(arg) {
const buf = cachedEncoder.encode(arg);
const ptr = wasm.__wbindgen_malloc(buf.length);
getUint8Memory().set(buf, ptr);
return [ptr, buf.length];
}
function getArrayU8FromWasm(ptr, len) {
const mem = getUint8Memory();
const slice = mem.slice(ptr, ptr + len);
return new Uint8Array(slice);
}
export function get_add_message(arg0) {
const [ptr0, len0] = passStringToWasm(arg0);
setGlobalArgument(len0, 0);
const ret = wasm.get_add_message(ptr0);
const len = getGlobalArgument(0);
const realRet = getArrayU8FromWasm(ret, len);
wasm.__wbindgen_free(ret, len * 1);
return realRet;
}
export function get_update_message(arg0, arg1, arg2) {
const [ptr2, len2] = passStringToWasm(arg2);
setGlobalArgument(len2, 0);
const ret = wasm.get_update_message(arg0, arg1 ? 1 : 0, ptr2);
const len = getGlobalArgument(0);
const realRet = getArrayU8FromWasm(ret, len);
wasm.__wbindgen_free(ret, len * 1);
return realRet;
}
export function get_remove_message(arg0, arg1, arg2) {
const [ptr2, len2] = passStringToWasm(arg2);
setGlobalArgument(len2, 0);
const ret = wasm.get_remove_message(arg0, arg1 ? 1 : 0, ptr2);
const len = getGlobalArgument(0);
const realRet = getArrayU8FromWasm(ret, len);
wasm.__wbindgen_free(ret, len * 1);
return realRet;
}
export function get_all_message() {
const ret = wasm.get_all_message();
const len = getGlobalArgument(0);
const realRet = getArrayU8FromWasm(ret, len);
wasm.__wbindgen_free(ret, len * 1);
return realRet;
}
export function __wbindgen_throw(ptr, len) {
throw new Error(getStringFromWasm(ptr, len));
}
This should work just fine so long as you are using webpack
4+, however the output would fail to run in Chrome since webpack
's wasm
module resolution uses synchronous compilation and Chrome refuses to execute synchronous compilation when a wasm
module bigger than 4kb. To get around this wasm-bindgen
has a sub-command wasm2es6js
that will convert your .wasm
into a base64 encoded string and compile it from there. The drawback here is that base64 encoded binary is about 33% larger.
The solution I have found works well for me is to make some modifications to the above file. First we want to remove the line that imports the wasm
module.
remove me
import * as wasm from './bincode_parser_bg';
From there we need to do two things, first is we need to fetch
the module manually and then use one of the asynchronous compilation methods, the second is to define our importObject
, this import object is our contract with the wasm
context for all of our shared functions.
The first step is pretty easy. at the top of your file you would add the following code block
fetch
let wasm;
export const booted = fetch('/bincode_parser_bg.wasm')
.then(res => res.arrayBuffer())
.then(buf => {
return WebAssembly.Instantiate(buf, importObject)
.then(mod => {
wasm = mod.instance.exports;
});
});
If you tried to run this now, you would encounter an error because we haven't defined the importObject
which we will do next but first lets go over what is happening.
We first define the module global variable wasm
because that is what the old module was imported as. Next we export a new property booted
, this is set to a promise returned from fetch
. When fetch
resolves the response we first want to convert that into an arrayBuffer
which is a special js array that will only include 8 bit whole numbers. Once we have converted it, we want to return the promise generated by WebAssembly.Instantiate
, this is one of the asynchronous methods for compiling wasm
. WebAssembly.Instantiate
takes in our bytes and the importObject and then resolves with the compiled and instantiated module. Once we have our module, we can use the instance
property to get an initialized version, and then we will set the exports
property to our module global wasm
resolving the exported promise.
Now lets construct our importObject
, because of the way JS
is executed, we probably want to do this at the bottom of our file.
importObject
let importObject = {
'./bincode_parser': {
__wbg_f_log_log_n: __wbg_f_log_log_n,
bincode_to_json: bincode_to_json,
get_add_message: get_add_message,
get_update_message: get_update_message,
get_remove_message: get_remove_message,
get_all_message: get_all_message,
__wbindgen_throw: __wbindgen_throw,
},
__wbindgen_placeholder__: {
__wbg_f_log_log_n: function() { },
bincode_to_json: function() { },
get_add_message: function() { },
get_update_message: function() { },
get_remove_message: function() { },
get_all_message: function() { },
__wbindgen_throw: function() { },
},
};
The wasm
ImportObject, will have 2 properties, the first has a key that starts with ./
followed by the original (no _bg or .wasm) module name, the second is going to be __wbindgen_placeholder__
. Both of the properties are will need to contain each of this file's export
ed items, not including booted. The first property is going to map to our concrete implementation while the second should just be empty versions of each type, here it is just functions but if you had exported a struct from your rust code it would be an empty object ({}
).
At this point we should have a fully working module, let's take a look at what our web app looks like and how we can incorporate it.