Technical Articles
Consuming WebAssembly modules from OpenUI5/SAPUI5 Applications
Introduction
In this article I will show you how to consume WebAssembly modules from OpenUI5/SAPUI5 application. We will fetch WebAssembly module (built with Rust), parse its metadata and render available functions and their signatures inside sap.m.List control!
We will learn following:
- Brief introduction to WebAssembly
- How to create WebAssembly modules
- How to fetch them in JavaScript
- How to call WebAssembly functions from our OpenUI5/SAPUI application
The final result is located at GitHub: https://github.com/gladimdim/webasm-ui5-loader.
What is WebAssembly
WebAssembly is a new binary format designed to be very compact and fast. WebAssembly target is to be almost the same performant as native applications written in C/C++. This format is now supported by all major browsers: Chrome, Safari, Edge and Firefox. You might already use WebAssembly apps on the web.
List of browsers with WebAssembly support:
WebAssembly is not a standalone language, though you can manually write binary code or use WebAssembly Text Format to create programs in it. Other languages must compile to WebAssembly. One of the best tools for WebAssembly are provided by Rust Language [https://www.rust-lang.org/] and C/C++.
You can read more about WebAssembly here:
How to create WebAssembly [wasm] modules
For this article we will use Rust language to compile to wasm binary format.
We will write several functions like sum and multiply in Rust and then compile them into wasm.
To compile Rust code to WebAssembly we will be using wasm-pack: https://github.com/rustwasm/wasm-pack
Rust project is located at GitHub inside subfolder: https://github.com/gladimdim/webasm-ui5-loader/tree/master/wasm-math
Also repository contains already built wasm module: https://github.com/gladimdim/webasm-ui5-loader/blob/master/webapp/wasm_math_bg.wasm
Rust code at https://github.com/gladimdim/webasm-ui5-loader/blob/master/wasm-math/src/lib.rs contains two functions:
#[wasm_bindgen]
pub fn add_two(a: i32, b: i32) -> i32 {
a + b
}
#[wasm_bindgen]
pub fn multiply_by(a: i32, b: i32) -> i32 {
a * b
}
We will call these functions from JavaScript (OpenUI5 application).
If you want to compile that code on your own, then follow detailed steps provided at this README: https://github.com/gladimdim/webasm-ui5-loader/tree/master/wasm-math
Once you compiled that project, you can copy the result (wasm file) into webapp folder.
How to call WebAssembly functions from JavaScript
GitHub repository is a valid OpenUI5/SAPUI5 application. So you can deploy it to SAP Web IDE and run the code there, or you can do it from your machine.
We will initialize WebAssembly module just inside onInit method of our Controller:
/***********************/
return Controller.extend('com.gladimdim.webasmloader.controller.App', {
onInit: function() {
this.aSearchFilters = [];
this.aTabFilters = [];
fetch('./wasm_math_bg.wasm')
/***********************/
We use standard Fetch API to load wasm file from the server:
fetch('./wasm_math_bg.wasm')
.then(response =>
response.arrayBuffer()
)
.then(bytes => {
return WebAssembly.instantiate(bytes);
})
From response we get ArrayBuffer and ask WebAssembly to instantiate the module from it.
WebAssembly.instantiate returns a promise, which resolves an object with our functions:
Now we can call our functions just from Dev Tools Console:
var { add_two } = results.instance.exports;
add_two(5, 3); // 8
var { multiply_by } = results.instance.exports;
multiply_by(10, 20); // 200
Reading MetaData from WebAssembly Module
For educational purpose, I decided to use https://www.npmjs.com/package/@webassemblyjs/wasm-parser library to get meta information about exposed functions.
We can use wasm-parser Decode function to create a JSON with needed info:
fetch('./wasm_math_bg.wasm')
.then(response =>
response.arrayBuffer()
)
.then(bytes => {
var ast = _webassemblyjs_wasmParser.decode(bytes);
// read only exported functions
var exportedFunctions = ast.body[0].fields.filter(f => f.name !== "memory" && f.type ===
"ModuleExport").map(f => f.name);
// update functionsMeta variable with a list of exported functions and their meta data
functionsMeta = ast.body[0].fields.filter(f => {
if (f.type === "Func" && exportedFunctions.indexOf(f.name.value) >= 0) {
return true;
} else {
return false;
}
});
// continue initialization process for WebAssembly module
return WebAssembly.instantiate(bytes);
})
Once ‘functionsMeta’ are initialized, we can create JSONModel and render our list:
.then(results => {
webAssemblyModule = results.instance;
var functions = {
"wasmFunctions": functionsMeta.map(exportedFn => {
return {
exec: webAssemblyModule.exports[exportedFn.name.value],
name: exportedFn.name.value,
arguments: exportedFn.signature.params,
results: exportedFn.signature.results[0]
};
})
};
oModel = new JSONModel(functions);
this.getView()
.setModel(oModel, "Functions");
});
Running OpenUI5 with WebAssembly
You can use official OpenUI5 Command Line Tools https://github.com/SAP/ui5-cli to run on your local machine.
Running Locally
Open command line and enter following commands:
npm install
ui5 serve
Then open this URL in the browser:
http://localhost:8080/index_ui5.html
Running in the SAP WebIDE
You can also run the same project in SAP WebIDE.
For this you have to clone the repo, then run index.html as you do with any other SAP WebIDE project.
You will see a list of exported functions from WebAssembly module. i32 is a name of WebAssembly type (integer 32bit). We bind them to ObjectListItem to let the user now, that function returns integer.
Hi Dmytro Gladkyi,
This is very exciting. Are there any plans within SAP to extend this and push some of the more complex parts of UI5 to WASM?
Cheers,
Nigel