Primary Menu

Tag Typescript

In this blog post I will explain how you can make an Angular app work with WebAssembly code. This combination of technologies can bring interesting advantages to web development and it is fairly simple to implement.

As I write this post, Angular is currently at version 5.1 and WebAssembly is still in its initial version, but it is making fast progress since Chrome, Edge, Firefox, and WebKit have reached a consensus on the binary format and API (see their roadmap).

Create the Angular App

Let’s start with the Angular app. If you are not familiar with Angular, you should visit its website and read its quick start guide and related documentation. You should be able to easily create a boilerplate app with the ng command (see angular CLI). We can start creating a new project called “ng-wasm”:

ng new ng-wasm

The generated project will have some basic source code and configuration files ready to be used. You should be able to serve the app right away and test it with the following command:

Create the WebAssembly Code

The second step now is the creation of the WebAssembly code. If you are not familiar with WebAssembly, you should visit their website and go through the documentation. You will have to download and install the emsdk package.

Angular will need access to the WASM code we will create, so the easiest solution for us is to create a cpp folder inside the src folder of the Angular project. The Angular project should then have a structure that looks like this:

Basically we have implemented two C functions that we will be able to call from Angular. Note that we have to decorate these functions with EMSCRIPTEN_KEEPALIVE, which prevents the compiler from inlining or removing them.

Note that I compile the C code with optimizations on (-O3 parameter), which makes the output more compact and efficient (if possible). The WASM=1 option tells the compiler to generate WebAssembly code (without this parameter, it would generate asm.js code instead). The EXTRA_EXPORTED_RUNTIME_METHODS=[‘ccall’] option is needed because we want to call the C functions from Javascript using the Module.ccall() javascript function (see the Angular code in the next section). I encourage you to read more about these parameters and play with them in order to see what errors or changes you will get.

Once you compile the C code, two files will be generated in the cpp/ folder:

In this code we implement two methods of the AppComponent class that will forward the call to our WebAssembly code generated in the previous section.

The first thing you should notice is the “declare var Module: any” at the top of the file. This is the typescript way of saying “there is a global variable named Module that I want to use in this scope”.The Module variable is actually a Javascript object used by the WebAssembly glue code. We declare it using type “any” because we don’t want typescript to complain about the things we will do with it. You should NOT do that in production code. It should be fairly simple for you to create a typescript definition file with class and method signatures (see my previous blog post where I discuss this).

Inside the multiply() member function we can call WebAssembly code using the Module.ccall() javascript function:

This HTML code adds two buttons to the page. The first button will call the multiply() function with two parameters (10.5 and 21.2), and the second button will call the getLength() function with “Testing String Length” parameter.

The Last Step

If you try to serve the existing source code with the ng serve command, you will notice that Angular doesn’t automatically load the WebAssembly code we have added to the src/cpp/ folder. We have to manually change the index.html file (inside the src/ folder) and add the following code snippet to the end of the <head> section:

This code imports the Javascript glue code generated by the WebAssembly compiler, but it also defines a Module.locateFile() function that will be used by WebAssembly to find the WASM file. By default, WebAssembly will try to find the WASM file at the root level of the application. In our case, we keep that file inside the cpp/ folder, so we have to prepend that folder’s name to the file path.

Now everything should be fine to go and the app should look like the screen below (with a bit of CSS makeup).

Conclusion

Angular and WebAssembly are two great technologies that can be used together without too much effort. There is no secret in this combination since both technologies are designed to work with web browsers and Javascript code is a common byproduct of their operations.

WebAssembly is still under development, but it has a huge potential towards native code performance, which is a dream yet to come true for web applications. Its roadmap is full of amazing features that serious web developers should never turn their back on.

The return statement in Javascript looks innocent and intuitive, but it hides a caveat that can break the logic of your code and lead to undefined behavior. The best way to illustrate this is to use a simple example, so let’s consider this function:

The function above works as expected and you don’t have to worry much about it. Now let’s imagine that you have to concatenate more strings inside the greeter function and you end up with a much longer line of code like this:

function greeter(name) {
return 'Hello, ' + name + ',\nThis is a long long long sentence.\nThis is another long sentence.';
}
console.log(greeter('Hugo'));

The code above also works fine if you keep it exactly as it is. You can notice that the string is too long to fit the width of the screen, so any decent developer would care about that and try to break that long line into smaller readable chunks. One possibility is:

function greeter(name) {
return
'Hello, ' + name + ',\n' +
'This is a long long long sentence.\n' +
'This is another long sentence.';
}
console.log(greeter('Hugo'));

B-I-N-G-O! The code above does NOT work as expected. This function returns undefined because the return statement is actually empty and Javascript doesn’t consider the next lines to be part of the return statement. There are some ways to fix this issue. One of them is to remove the line break after the return keyword, like this:

function greeter(name) {
return 'Hello, ' + name + ',\n' +
'This is a long long long sentence.\n' +
'This is another long sentence.';
}
console.log(greeter('Hugo'));

You can notice that the code above is a bit unaligned. A perfectionist (like me) would add the line break after the return in order to fix the alignment problem, but this actually creates the other (much bigger) problem. Sigh.

Another way of fixing the code is to use parenthesis around the return value. In this case the alignment isn’t a problem:

function greeter(name) {
return (
'Hello, ' + name + ',\n' +
'This is a long long long sentence.\n' +
'This is another long sentence.'
);
}

Parentheses are valid in this case because the return statement can be followed by an expression. It is quite uncommon to see such syntax, but in this case it plays an important role. This is one of the many details about the language that you have to be aware of in order to play it safe. If you develop code in other languages — like Java or C++ — you know that such code without the parentheses would work perfectly fine in those languages, so it would be fairly easy to forget to use them when you switch back to Javascript.

Typescript is better

In Typescript we could have some similar code like this:

function greeter(name: string): string {
return
'Hello, ' + name + ',\n'
'This is a long long long sentence.\n' +
'This is another long sentence.';
}
console.log(greeter('Hugo'));

If you try to compile this code with Typescript you get the following error message:

code.ts(3,8): error TS7027: Unreachable code detected.

So it basically says that line 3 has unreachable code and now you have to fix it. This is a much better world compared to pure javascript development since you know that this issue will not waste your time later.

If you use Typescript, make sure you have the compiler option “allowUnreachableCode” enabled (otherwise you will not see the error above). Read more about this flag on the compiler options page.

One question may come to your mind at this point: should Typescript fix the code automatically by generating JS code that doesn’t contain the line break after the return statement? Nope. The number of scenarios that this issue could happen is huge, so it is much safer to just warn the developer instead of trying to fix the code silently. I think Typescript is doing a good job here (kudos to Microsoft).

Conclusion

The return statement issue described in this post is just one of many caveats of the Javascript language. It should remind you that Javascript alone can be a treacherous path and you should definitely consider better alternatives like Typescript in your development. Javascript alone can make the software maintenance a nightmare in the long run, so serious developers must look for better alternatives in order to detect and fix mistakes as early as possible. Be productive and stay safe.

This week I implemented a simple 3D experiment with Typescript, ThreeJS and Ammo.js. It works like an FPS game where you can navigate with the mouse pointer and W-A-S-D keys, and you can also shoot cannon balls with the mouse button.

Using Typescript

Typescript is a great language that compiles to Javascript code. If you are a web developer and have never used this language before, you should check it out immediately because it has a lot of interesting things that can make your life (as a web programmer) much easier. You know that Javascript is a powerful language, but alone it can make the maintenance of big projects a nightmare. Typescript is a great step towards high quality maintainable code because it is a typed superset of Javascript.

The challenge of using Typescript with some external libraries is that you need the type definition files of those libraries to compile your code. A type definition file is a piece of typescript code that contains the declaration of types, classes, interfaces and functions of a library. It doesn’t provide implementation details, only types and signatures. This allows Typescript to analyze your code and detect programming errors. For example, check the ThreeJS definition file here:

DefinitelyTyped is a website that aggregates lots of definition files and it is a great asset for Typescript developers. Sometimes it doesn’t contain definition files that you need and this was the case of the Ammo.js library I used in my experiment.

No definition files – What should I do?

When there is no definition file available for the library you want to use, you can build one your own. Typescript can certainly guide you through this process. The compiler errors reported by Typescript will show you exactly what is missing in the definition file. For example, let’s try to declare a variable like this:

let physicsWorld: Ammo.btDiscreteDynamicsWorld;

You can start with an empty definition file (ammo.d.ts). Compiling the code above will show this message:

Cannot find namespace 'Ammo'.

So you can use this information to fix your custom definition file for that library. In this case, you can just add an empty namespace like this:

declare namespace Ammo {
}

After that, if you try to compile again the error message will change to:

Module 'Ammo' has no exported member 'btDiscreteDynamicsWorld'.

So you can change your definition file to:

declare namespace Ammo {
export class btDiscreteDynamicsWorld {
}
}

Following this pattern, you can basically add the missing information piece by piece to the definition file until your project is fully compilable. Of course you have to keep an eye on the real library code and make sure your declarations are consistent with the real implementation. For Ammo.js, you can see below the final definition file I created. Note that there is no implementation code, only types and signatures.

You should realize that my type definitions for Ammo.jsare far from complete, considering what the library does. Ammo is a huge library and it contains a lot more things that my code will not use at this point. This is okay and the main point here is that the file I created is enough for me to compile my experiment and keep moving. If I need more methods from Ammo.js, I can adjust that file as needed and move on.

Typescript and browser differences

Sometimes Typescript will NOT understand your Javascript code and you will have to deal with it. Let me give you a clear example:

The code above is syntactically correct and it looks for the Pointer Lock API in the current browser. Typescript complains about this code with the following error message:

Property 'mozRequestPointerLock' does not exist on type 'HTMLElement'.
Property 'webkitRequestPointerLock' does not exist on type 'HTMLElement'.

Those methods are browser-specific and typescript doesn’t recognize them. We have to fix this error message and one possible solution is to assign the document.body value to a variable of type “any”. This will prevent typescript from checking if those properties belong to the HTMLElement type:

There are other ways of handling such cases, but I won’t explain them in this post. One great thing about Typescript is that it doesn’t stop the compilation when it finds errors like the one above. It simply generates the javascript output as if the code were correct and you can clean up that error message later.

Conclusions

Working with Typescript is an amazing experience. I believe that Microsoft is doing a great job with this language and contributing to the future of web development with great ideas. My experiment with ThreeJS and Ammo.js is just in the beginning. I have a good experience with the BulletPhysics library (see my personal projects) and this should allow me to expand the code and build more cool demos, examples and games.