Issue
I integrated some WASM code (compiled from Go code) into Angular to use some functions. At the moment this is done only in one place and is thus not shared throughout the whole app. I just used the "standard" procedure for WASM and Go:
let go = new Go();
WebAssembly.instantiateStreaming(fetch('mywasm.wasm'), go.importObject).then((res) => {
go.run(res.instance);
myCoolWasmFunction();
});
However, I would like to execute WASM in multiple parts of the app and thus tried to move this into a service. I was able to use an RxJS subject and listen to "execution requests" in that function after go.run(...)
, but I could not return anything to other parts of the app.
Basically, I am searching for a clean and usable way to execute different functions exposed by wasm in the Angular app. Should I just put the wasm stuff into the index.html
and create a service that just calls those "globally available" functions? How would I enable angular to recognize those, just with a .d.ts
file?
Solution
I solved this with the help of this Github Repo. It is as simple as creating a public variable inside the service and, when WASM was loaded, setting the exported WASM functions to that variable so they can be called from outside the service. For the following example I added a small typescript interface to make it work with type safety:
So, in the WASM service could look like this:
private Suite: WasmSuite; // Here the exported functions are stored after wasm was initiated
/*
WasmSuite is defined like this:
type MyFunctionInterface = (input: string) => string;
interface WasmSuite {
myFunction: MyFunctionInterface;
}
*/
// This is just to let components know when WASM is ready
public ready: BehaviorSubject<boolean> = new BehaviorSubject(false);
constructor() {
// Init wasm, then update the ready state
this.init().then(_ => {
this.ready.next(true);
});
}
private async init() {
let go = new Go();
return WebAssembly.instantiateStreaming(
fetch('assets/main.wasm'),
go.importObject
).then((res) => {
go.run(res.instance);
// Set the Suite to an object containing the functions. The casting of the function is somewhat optional, but I think it's good practice.
this.Suite = {
myFunction: my_exported_func as MyFunctionInterface,
// "my_exported_func" is what I exported in Go via js.Global().Set("my_exported_func", js.FuncOf(myGoFunc))
};
});
}
public callMyFunction(input: string) {
// I like to publish methods to components instead of the suite object, so this is just an "interface" between callers and WASM.
return this.Suite.myFunction(input);
}
Answered By - Janis Jansen
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.