Introducing WebAssembly
In this section, we will look at how WebAssembly works. One way of running Blazor is by using WebAssembly, but for now, let’s focus on what WebAssembly is.
WebAssembly is a binary instruction format that is compiled and, therefore, smaller. It is designed for native speeds, which means that when it comes to speed, it is closer to C++ than it is to JavaScript. When loading JavaScript, the JavaScript files (or inline JavaScript) are downloaded, parsed, optimized, and JIT-compiled; most of those steps are not needed for WebAssembly.
WebAssembly has a very strict security model that protects users from buggy or malicious code. It runs within a sandbox and cannot escape that sandbox without going through the appropriate APIs. Suppose you want to communicate outside WebAssembly, for example, by changing the Document Object Model (DOM) or downloading a file from the web. In that case, you will need to do that with JavaScript interop (more on that later; don’t worry – Blazor will solve this for us).
Let’s look at some code to get a bit more familiar with WebAssembly.
In this section, we will create an app that sums two numbers and returns the result, written in C (to be honest, this is the level of C I’m comfortable with).
We can compile C into WebAssembly but it requires the installation of some tooling, so we will not do this all the way. The point here is just to give us a feel for how WebAssembly works under the hood. Consider this code:
int main() {
return 1+2;
}
The result of this will be the number 3
.
WebAssembly is a stack machine language, which means that it uses a stack to perform its operations.
Consider this code:
1+2
Most compilers will optimize the code and return 3
.
But let’s assume that all the instructions should be executed. This is the way WebAssembly would do things:
- It will start by pushing
1
onto the stack (instruction: i32.const 1
), followed by pushing2
onto the stack (instruction: i32.const 2
). At this point, the stack contains1
and2
. - Then, we must execute the add instruction (
i32.add
), which will pop (get
) the two top values (1
and2
) from the stack, add them up, and push the new value onto the stack (3
).
This demo shows that we can build WebAssembly from C code. Even though we never need to go to this level to understand WebAssembly (Blazor handles all of that for us), we will use C code and other libraries compiled into WebAssembly later in the book (Chapter 16, Going Deeper into WebAssembly).
OTHER LANGUAGES
Generally, it is only low-level languages that can be compiled into WebAssembly (such as C or Rust). However, there are a plethora of languages that can run on top of WebAssembly. Here is a great collection of some of these languages: https://github.com/appcypher/awesome-wasm-langs.
WebAssembly is super performant (near-native speeds) – so performant that game engines have already adopted this technology for that very reason. Unity, as well as Unreal Engine, can be compiled into WebAssembly.
Here are a couple of examples of games running on top of WebAssembly:
- Angry Bots (Unity): https://beta.unity3d.com/jonas/AngryBots/
- Doom: https://wasm.continuation-labs.com/d3demo/
This is a great list of different WebAssembly projects: https://github.com/mbasso/awesome-wasm.
This section touched the surface of how WebAssembly works; in most cases, you won’t need to know much more. We will dive into how Blazor uses this technology later in this chapter.
To write Blazor apps, we can leverage the power of .NET 8, which we’ll look at next.