JavaScript to Wasi Enabled Wasm: Portable JavaScript Composition

Rate this content
Bookmark

JavaScript is no longer a language confined to the browsers. New standards are enabling fully portable, lightweight runtimes, to make JavaScript the definitive language for isomorphic applications. 

Let's explore use-cases, some experimental, some consolidated, to take our Wasm game with JavaScript, to the next level.

Natalia Venditto
Natalia Venditto
21 min
15 Feb, 2024

Comments

Sign in or register to post your comment.

Video Summary and Transcription

JavaScript code is converted to low-level binaries by JavaScript engines like MV8, Chakra, and SpiderMonkey. WebAssembly allows writing code in other languages and compiling it to run on a JavaScript engine. External functions can be imported in WebAssembly using the import statement. WebAssembly can run in non-browser scenarios with additional interfaces like WASI and provides memory isolation. The Jco toolchain is an experimental tool for componentizing JavaScript code into WASM modules.

1. Introduction to JavaScript and WebAssembly

Short description:

I'm a principal lead for JavaScript developer experience on Azure, covering integrations, hosting services, and compute. JavaScript code goes through a flow of execution on the browser, from parsing to code generation. JavaScript engines like MV8, Chakra, and SpiderMonkey convert the code to low-level binaries. WebAssembly is a binary instructions format that allows us to write code in other languages and compile it to run on a JavaScript engine. It works based on imports and exports.

Hello, everyone. My name is Natalia Bendito and I'm a principal lead for JavaScript developer experience end-to-end across the many services and tools that can be used by JavaScript developers to build applications on Azure. That ranges from integrations like GitHub Actions to VS Code extensions, hosting services like Azure Static Web Apps, or compute like Azure Container Apps or Azure Functions.

When we build JavaScript applications, we know that our code or scripts are basically going to go through this flow of execution on the browser. Each instruction goes through this just-in-time journey. The parser or JavaScript engine generates a hierarchical structure called the abstract syntax tree or AST. For example, a variable declaration is a CAPS, variable CAPS declaration, node construct in AST, which the interpreter reads and generates high-level binary code or byte code from. Finally, the compiler generates low-level binary code that speaks to the CPU in a way that can be understood according to the processor or CPU architecture. All of this again happens just-in-time. This flow is mostly the work of the JavaScript engine. MV8 is one of the most popular, but there is also Chakra, there's SpiderMonkey, there are others. The generated machine code may be optimized for a specific set of instructions that are, again, optimal for a specific architecture, as we mentioned before. This means we are converting our high-level JavaScript code to low-level binaries. JavaScript engines can take care of the initialization of the environment or do take care of the initialization of the environment. They add built-in functions and they also handle or run our application code. The engine also provides the runtime, where the application is going to be running on. JavaScript scripts run on a JavaScript engine, obviously, but what does also run on a JavaScript engine, if you can think about it, at that low level, by the way? That's, of course, WebAssembly.

What is WebAssembly more concretely, or Wasm, as some may refer to? It's not really a language. It's a binary instructions format. Compilation target means that we write our code in the language we prefer as long as it has a Wasm tool chain or compiler that allows us to do so and we compile it to binary as Wasm to run at that low level that we were describing before. How does WebAssembly actually work? Let's imagine we have a program written in C, C++, RAS, or any other language that is supported, and we want to compile it to Wasm. We use its corresponding tool chain or a set of developer tools, and that's what I meant before by is supported. It has this set of developer tools and compilers, which will emit that code as a module, which imports and with imports, sorry, and exports. Then we can import it into our JavaScript to be run with a JavaScript engine using WebAssembly JavaScript bindings or the JavaScript API. Wasm does not really define any APIs. It works like we mentioned on the basis of imports and exports. This is an example of a module written in WebAssembly text. Let's walk through this cycle. If I was going to describe each one of the lines and things that are in this code, it would take a very long time, and it would be a little bit exhausting. But we can define the sections.

2. Using External Functions in WebAssembly

Short description:

The import statement is used to import an external function, such as println from the environment module. The function section exports the function hello world. The memory section declares the size of the memory, and the data section initializes the memory with a string. When importing the module in JavaScript, we fetch the module, process the response, compile the binary data, and create an instance of the module. We can redirect the output of the print line function to console.log. WebAssembly allows us to run CPU-intensive operations at a lower level and compose user interfaces. Page find is an example of using WebAssembly for document ingestion, indexing, and full-text search on the client side. We can achieve this in a static website using WebAssembly.

I think that it's important to start with the import statement that is used to import an external function because we don't have anything in the Wasm native APIs. We are importing this external function named println from a module called environment. This function takes a single parameter of type I32 or 32 bit integer. The important function is given the name dollar println.

Now in the next section, we have the function section. The function is exported with the name hello underscore world. Then we have another section, the memory section, which basically declares the size of the memory. In this case, one page. Finally, we have the data section that initializes the memory, in this case at offset zero with a utf-8 string, hello world of JavaScript.

Now what I think is really interesting is what happens in the JavaScript that is importing this module or fetching this module. We're fetching the module we exported to a file named hello underscore world.wasm. Then the response is processed using response.arrive buffer to obtain the module's binary data. We then use the WebAssembly.compile function to compile the binary data we got from the previous step into a WebAssembly module. We use the WebAssembly.instance constructor to create an instance of the compiled WebAssembly module. As you can see, there is an environment object provided in the second parameter of the constructor, which includes an important function named print line. Do you remember the previous what file? This important function is mapped to console log. The purpose of this mapping is to redirect any output of the WebAssembly module's print line function, as defined in the WebAssembly text code that we provided before, to the JavaScript console.log function. And finally, the exported function hello underscore world is invoked from the WebAssembly module using instance.exports.hello world or hello underscore world.

Since we have the ability to fetch and run Wasm, as we just saw, as part of our JavaScript programs, we can compose user interfaces where we run CPU intensive operations at a much lower level or lower level than our typical JavaScript programs run in a more performant way. Let's explore a specific use case of this type of composition. Let's propose we have a static website, like one site created with any meta framework today, like Astro11t and so on, using static data fetching. And we want to run a search functionality for that static content. Well, we can do it with JavaScript client side, but we can also use WebAssembly. So let's use it. And page find is a great example of a Wasm feature that does, in this case, document ingestion, indexing, and runs full text search, filtering, sorting, et cetera, all on the client side at a very low level in WebAssembly. Let me show you now exactly how page find works. We're on the documentation site, but we will go to Starlight, a framework to build documentation sites with Astro. If we pay attention to the top left, we see we have a search bar. Although this is a static generated site, how does this work? Let's run a search for something like div. We notice we get immediate results.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Modern Web Debugging
JSNation 2023JSNation 2023
29 min
Modern Web Debugging
Top Content
Few developers enjoy debugging, and debugging can be complex for modern web apps because of the multiple frameworks, languages, and libraries used. But, developer tools have come a long way in making the process easier. In this talk, Jecelyn will dig into the modern state of debugging, improvements in DevTools, and how you can use them to reliably debug your apps.
Utilising Rust from Vue with WebAssembly
Vue.js London Live 2021Vue.js London Live 2021
8 min
Utilising Rust from Vue with WebAssembly
Top Content
Rust is a new language for writing high-performance code, that can be compiled to WebAssembly, and run within the browser. In this talk you will be taken through how you can integrate Rust, within a Vue application, in a way that's painless and easy. With examples on how to interact with Rust from JavaScript, and some of the gotchas to be aware of.
The Future of Performance Tooling
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Top Content
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
Making JavaScript on WebAssembly Fast
JSNation Live 2021JSNation Live 2021
29 min
Making JavaScript on WebAssembly Fast
Top Content
JavaScript in the browser runs many times faster than it did two decades ago. And that happened because the browser vendors spent that time working on intensive performance optimizations in their JavaScript engines.Because of this optimization work, JavaScript is now running in many places besides the browser. But there are still some environments where the JS engines can’t apply those optimizations in the right way to make things fast.We’re working to solve this, beginning a whole new wave of JavaScript optimization work. We’re improving JavaScript performance for entirely different environments, where different rules apply. And this is possible because of WebAssembly. In this talk, I'll explain how this all works and what's coming next.
Crafting the Impossible: X86 Virtualization in the Browser with WebAssembly
JSNation 2022JSNation 2022
21 min
Crafting the Impossible: X86 Virtualization in the Browser with WebAssembly
WebAssembly is a browser feature designed to bring predictable high performance to web applications, but its capabilities are often misunderstood.
This talk will explore how WebAssembly is different from JavaScript, from the point of view of both the developer and the browser engine, with a particular focus on the V8/Chrome implementation.
WebVM is our solution to efficiently run unmodified x86 binaries in the browser and showcases what can be done with WebAssembly today. A high level overview of the project components, including the JIT engine, the Linux emulation layer and the storage backend will be discussed, followed by live demos.
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
You will learn about one of the most popular package managers for JavaScript and its advantages over npm and Yarn.A brief history of JavaScript package managersThe isolated node_modules structure created pnpmWhat makes pnpm so fastWhat makes pnpm disk space efficientMonorepo supportManaging Node.js versions with pnpm

Workshops on related topic

React, TypeScript, and TDD
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.