{"id":1495,"date":"2022-01-05T02:33:02","date_gmt":"2022-01-05T01:33:02","guid":{"rendered":"https:\/\/nguenkam.com\/blog\/?p=1495"},"modified":"2022-01-05T02:35:50","modified_gmt":"2022-01-05T01:35:50","slug":"angular-webassembly","status":"publish","type":"post","link":"https:\/\/nguenkam.com\/blog\/index.php\/2022\/01\/05\/angular-webassembly\/","title":{"rendered":"Angular &#038; WebAssembly"},"content":{"rendered":"\n<p><strong><em>What is Web Assembly?<\/em><\/strong><\/p>\n\n\n\n<p>WebAssembly (<strong>Wasm<\/strong>) is a new way to run code on the web.It is a binary instruction format and can run in the most popular browsers today! ( <em>currently supported by Firefox, Chrome, Edge and Safari.<\/em>)<\/p>\n\n\n\n<p> Until now, only JavaScript has been used to create applications of this kind.But It is no longer the only language you can run on the web. Web browsers can run any language now, if that language has a\u00a0WebAssembly compiler .<\/p>\n\n\n\n<p><strong>WASM,<\/strong> is the second universal programming language that all web browsers can understand and run. However, you\u2019re not going to be writing scripts in WebAssembly yourself\u2014it\u2019s a low level assembly language, designed to be very close to compiled machine code, and very close to native performance.<\/p>\n\n\n\n<p>The main advantage of Web Assembly that it is fast. (Almost) As fast as a native program.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4>JavaScript is slow!<\/h4>\n\n\n\n<p>Compared with native programs written in C or C++ JavaScript is very slow. This is because it is not directly translated into processor instructions, but runs in a virtual machine instead.The additional layer of the virtual machine costs JavaScript quite a bit of performance.<\/p>\n\n\n\n<p>Furthermore, JavaScript is not a compiled language. That means, that the code has to be compiled at runtime to be executed. Because this process is typically relatively slow, JavaScript uses a technique called Just-In-Time compilation (JIT). Although JIT reduces the load-time of the program a lot, it is not as fast a executing pre-compiled programs.<\/p>\n\n\n\n<h4>Web Assembly to the rescue!<\/h4>\n\n\n\n<p>No, seriously, JavaScript is just fine for most web applications. It is easy to use and especially with modern frameworks quite fast.<\/p>\n\n\n\n<p>But for certain applications it is not fast enough.<\/p>\n\n\n\n<p>These are typically applications that require a lot of calculations.<\/p>\n\n\n\n<p>That is where Web Assembly shines. Examples for that are applications like image manipulations or games.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h4>Example: <span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>A C-Program in Angular<\/strong><\/span><\/h4>\n\n\n\n<p>Web Assembly can be generated from many languages such as C, C++ or Rust. There is even an experimental project that compiles TypeScript to Web Assembly.<\/p>\n\n\n\n<p>For this example, we will keep it simple and compile a very basic C program.<\/p>\n\n\n\n<p>Let\u00b4s create a folder called &#8220;wasm&#8221; inside of our project root. Inside of that folder, create a file called &#8220;fibonacci.c&#8221;.<\/p>\n\n\n\n<p>Our example will calculate the Fibonacci number of any number<\/p>\n\n\n\n<p>The C program looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int fibonacci(int n)\r\n{\r\n    if (n == 0 || n == 1)\r\n        return n;\r\n    else\r\n        return (fibonacci(n - 1) + fibonacci(n - 2));\r\n}<\/code><\/pre>\n\n\n\n<p><span class=\"has-inline-color has-vivid-red-color\"><strong>Exposing the Function to JavaScript<\/strong><\/span><\/p>\n\n\n\n<p>What we want to do here, is to make the Fibonacci function callable from our JavaScript code.<\/p>\n\n\n\n<p>Therefore, we need to mark it with a special decorator. For this decorator, we need to include emscripten.h.<\/p>\n\n\n\n<p>Afterwards, the program looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;emscripten.h>\r\n\r\nint EMSCRIPTEN_KEEPALIVE fibonacci(int n)\r\n{\r\n    if (n == 0 || n == 1)\r\n        return n;\r\n    else\r\n        return (fibonacci(n - 1) + fibonacci(n - 2));\r\n}<\/code><\/pre>\n\n\n\n<ul><li><strong>Set Up a new Angular Project<\/strong><\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>ng new angular-wasm<\/code><\/pre>\n\n\n\n<ul><li><strong>We also need the typings for the Web Assembly JavaScript API. Let&#8217;s install them:<\/strong><\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install @types\/webassembly-js-api --dev --save<\/code><\/pre>\n\n\n\n<ul><li><strong>Installing the Web assembly compiler<\/strong><\/li><\/ul>\n\n\n\n<p>To install the Web Assembly compiler, please follow these instructions:\u00a0<a href=\"http:\/\/webassembly.org\/getting-started\/developers-guide\/\">Web Assembly Getting Started<\/a>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>If you are on Windows, you might have to add the path of the emsdk to you PATH variables<\/p><\/blockquote>\n\n\n\n<ul><li><strong>Compiling C to WASM<\/strong><\/li><\/ul>\n\n\n\n<p>To use our (previous &#8220;C&#8221; code ) function, we need to compile it to Web Assembly first, because the browser does not understand C.<\/p>\n\n\n\n<p>To do that, we are using the compiler we have installed before.<\/p>\n\n\n\n<p>The command to do so looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>emcc wasm\/fibonacci.c -Os -s WASM=1 -s MODULARIZE=1 -o wasm\/fibonacci.js<\/code><\/pre>\n\n\n\n<ol><li>The <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">-Os<\/span><\/em> options defines the grade of optimizations performed. We use a quite high grade here.<\/li><li>Besides WASM, the compiler will also generate a JavaScript file. This file includes some glue-code, that handles the communication between WASM and JavaScript.<\/li><li> With the <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">MODULARIZE=1<\/span><\/em> option we tell the compiler to wrap that code into a module. That way it is much easier to consume in our angular app.<\/li><\/ol>\n\n\n\n<p><\/p>\n\n\n\n<p>The result of that command should be two new files: <em><strong>fibonacci.js<\/strong><\/em> and <em><strong>fibonacci.wasm<\/strong><\/em>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<ul><li><strong>Wrapping Web Assembly in an Angular Service<\/strong><\/li><\/ul>\n\n\n\n<p>Now we can use our WASM function in angular. The best place for these utility-style of functions are in a separate service. So we are going to create a new service called WasmService.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng generate service wasm<\/code><\/pre>\n\n\n\n<p>Unfortunately, using WASM modules is not as quite as easy as using plain JavaScript ones.<\/p>\n\n\n\n<p>We do not only have to import our WASM JavaScript glue-code module, but also have to import the was file itself using the file-loader<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import * as Module from '.\/..\/..\/wasm\/fibonacci.js'\nimport '!!file-loader?\nname=wasm\/fibonacci.wasm!..\/..\/wasm\/fibonacci.wasm';<\/code><\/pre>\n\n\n\n<p><em><span class=\"has-inline-color has-vivid-red-color\">Unfortunately, that way the WASM file is not included in the bundle itself, but is provided as separate file.<\/span><\/em><\/p>\n\n\n\n<ul><li><strong>Instantiate Web Assembly<\/strong><\/li><\/ul>\n\n\n\n<p>To use the WASM-file at runtime, it has to be fetched from the provided URL and converted into a byte array.<\/p>\n\n\n\n<p>To do that, we create a new method inside of our service called &#8220;instantiateWasm&#8221;.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private async instantiateWasm(url: string){\r\n  \/\/ fetch the wasm file\r\n  const wasmFile = await fetch(url);\r\n\r\n  \/\/ convert it into a binary array\r\n  const buffer = await wasmFile.arrayBuffer();\r\n  const binary = new Uint8Array(buffer);\r\n\r\n  \/\/ create module arguments\r\n  \/\/ including the wasm-file\r\n  const moduleArgs = {\r\n    wasmBinary: binary,\r\n    onRuntimeInitialized: () => {\r\n      \/\/ TODO\r\n    }\r\n  };\r\n\r\n  \/\/ instantiate the module\r\n  this.module = Module(moduleArgs);\r\n}<\/code><\/pre>\n\n\n\n<p>Notice that we also need to create a property on the service called &#8220;module&#8221;. This property will contain the module, with all the functions that it has, including our Fibonacci function.<\/p>\n\n\n\n<p>We can now call that method in the constructor of our service:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>constructor() {\r\n  this.instantiateWasm('wasm\/fibonacci.wasm');\r\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>To provide that Fibonacci function to our angular components in a convenient way, we are going to create a method with the same name in our service.<\/p>\n\n\n\n<p>Inside of that method, we are just calling the WASM function.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public fibonacci(input: number): number{\r\n return this.module._fibonacci(input)\n}<\/code><\/pre>\n\n\n\n<p><em><span class=\"has-inline-color has-vivid-red-color\">Notice that all functions that are actually <strong>WASM<\/strong> functions start with an <strong>underscore<\/strong>.<\/span><\/em><\/p>\n\n\n\n<ul><li><strong>Delaying Functions until Web Assembly is loaded<\/strong><\/li><\/ul>\n\n\n\n<p>That&#8217;s it! We can now use the service just as any other angular service.<\/p>\n\n\n\n<p>But there is a problem!<\/p>\n\n\n\n<p>Our instantiateWasm method is async and actually takes a while to load the Web Assembly module. When someone calls our Fibonacci method in the meantime, the module property is still undefined.<\/p>\n\n\n\n<p><em>To solve that problem, we change our Fibonacci method to return an observable. With the help of the observable, we can delay the execution of the method until our service is ready<\/em>.<\/p>\n\n\n\n<p>Furthermore, we need to create a BehaviorSubject in our service.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wasmReady = new BehaviorSubject&lt;boolean>(false)<\/code><\/pre>\n\n\n\n<p>We update this Subject, once our service is ready.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ update this in instantiateWasm()\r\nconst moduleArgs = {\r\n  wasmBinary: binary,\r\n  onRuntimeInitialized: () => {\r\n    this.wasmReady.next(true) \/\/ &lt;-- this line\r\n  },\r\n}<\/code><\/pre>\n\n\n\n<p>We then filter that observable in our Fibonacci method to only continue when the value of the subject is true. For that, we use the filter mehtod from rxjs. We are also going to need the take and the mergeMap operator.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { filter} from 'rxjs\/operators';<\/code><\/pre>\n\n\n\n<p>The actual pipeline then looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public fibonacci(input: number): Observable&lt;number> {\r\n    return this.wasmReady.pipe(filter(value => value === true)).pipe(\r\n      map(() => {\r\n        return this.module._fibonacci(input);\r\n      })\r\n    );\r\n  }<\/code><\/pre>\n\n\n\n<h4>The Full WASM Service Code<\/h4>\n\n\n\n<p>Here is what the service should look like once you are done:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Injectable } from '@angular\/core'\r\nimport { Observable, BehaviorSubject } from 'rxjs'\r\nimport { filter, map } from 'rxjs\/operators'\r\n\r\nimport * as Module from '.\/..\/..\/wasm\/fibonacci.js'\r\nimport '!!file-loader?name=wasm\/fibonacci.wasm!..\/..\/wasm\/fibonacci.wasm'\r\n\r\n@Injectable()\r\nexport class WasmService {\r\n  module: any\r\n\r\n  wasmReady = new BehaviorSubject&lt;boolean>(false)\r\n\r\n  constructor() {\r\n    this.instantiateWasm('wasm\/fibonacci.wasm')\r\n  }\r\n\r\n  private async instantiateWasm(url: string) {\r\n    \/\/ fetch the wasm file\r\n    const wasmFile = await fetch(url)\r\n\r\n    \/\/ convert it into a binary array\r\n    const buffer = await wasmFile.arrayBuffer()\r\n    const binary = new Uint8Array(buffer)\r\n\r\n    \/\/ create module arguments\r\n    \/\/ including the wasm-file\r\n    const moduleArgs = {\r\n      wasmBinary: binary,\r\n      onRuntimeInitialized: () => {\r\n        this.wasmReady.next(true)\r\n      },\r\n    }\r\n\r\n    \/\/ instantiate the module\r\n    this.module = Module(moduleArgs)\r\n  }\r\n\r\n  public fibonacci(input: number): Observable&lt;number> {\r\n    return this.wasmReady.pipe(filter(value => value === true)).pipe(\r\n      map(() => {\r\n        return this.module._fibonacci(input)\r\n      })\r\n    )\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h5>References:<\/h5>\n\n\n\n<p><a href=\"https:\/\/www.cloudsavvyit.com\/13696\/why-webassembly-frameworks-are-the-future-of-the-web\/\">https:\/\/www.cloudsavvyit.com\/13696\/why-webassembly-frameworks-are-the-future-of-the-web\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/malcoded.com\/posts\/web-assembly-angular\/\">https:\/\/malcoded.com\/posts\/web-assembly-angular\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>What is Web Assembly? WebAssembly (Wasm) is a new way to run code on the web.It is a binary instruction format and can run in the most popular browsers today! ( currently supported by Firefox, Chrome, Edge and Safari.) Until now, only JavaScript has been used to create applications of this kind.But It is no [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1496,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[37,419],"tags":[421,423,420,422],"_links":{"self":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1495"}],"collection":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=1495"}],"version-history":[{"count":4,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1495\/revisions"}],"predecessor-version":[{"id":1527,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1495\/revisions\/1527"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/1496"}],"wp:attachment":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=1495"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=1495"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=1495"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}