WebAssembly: What it is, How it Works, Potential and Practical Guide



WebAssembly (abbreviated to Wasm) is a portable, performant binary language designed to run code close to native speed directly in the browser. In this article, we'll explore what it is, how it works, its capabilities, support in modern browsers, and even provide a practical end-to-end example with Rust and JavaScript.

🔗 Do you like Techelopment? Check out the site for all the details!

What is WebAssembly?

WebAssembly is an open standard (W3C) designed to bring compiled code from languages ​​such as Rust, C/C++, Go and many others to the web, offering very high performance and security in a sandbox environment.

Standardization

Wasm was officially recognized as a web standard by W3C in 2019.

Main features:

  • Portability: it can run anywhere, even outside the browser (portable and optimized binary format).

  • High Performance: Speed ​​comparable to native code.

  • Security: Execution in sandbox, without direct access to the system.

  • Interoperability: Can efficiently interoperate with JavaScript and Web APIs.


How WebAssembly Works

Code written in languages ​​like Rust is compiled into a .wasm module, which can then be loaded into the browser via JavaScript. The browser runs that module in a sandbox with near-native performance.

Typical pipeline:

  1. Write the code in a language that compiles to Wasm (e.g. Rust).

  2. Compile into a .wasm module.

  3. Load it in the browser using JavaScript.

  4. Run and interact with the data via calls between Wasm and JS.

Example JS to load a Wasm module:

fetch('module.wasm')
 .then(res => res.arrayBuffer())
 .then(bytes => WebAssembly.instantiate(bytes))
 .then(obj => {
   console.log(obj.instance.exports.myFunction());
});

Practical end-to-end example: WebAssembly + JavaScript

Let's see a complete example of how to create a Wasm module in Rust, compile it, and use it in HTML/JavaScript to get and print a processed object.

In this example, we will see how to:
  1. Install Rust and create a Rust project

  2. Write a simple function in Rust that processes some information.

  3. Compile it into a WebAssembly module (.wasm) using wasm-pack.

  4. Load the module into an HTML page with JavaScript.

  5. Print an object returned by the module to console.log Wasm.


1. Install Rust and wasm-pack (Linux, macOS, Windows)

Linux/macOS

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install wasm-pack

Windows

  • Go to https://rustup.rs and download the installer for Windows.

  • After installation, open PowerShell and install:

    cargo install wasm-pack
Alternatively if you use nodejs:
npm install -g wasm-pack

2. Create the Rust project

cargo new wasm-demo --lib
cd wasm-demo

Edit Cargo.toml:

[package]
name = "wasm_demo"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
serde = { version = "1.0", features = ["derive"] }
Edit src/lib.rs:
use wasm_bindgen::prelude::*;
use serde::{Serialize};

#[derive(Serialize)]
pub struct ResultObject { 
    pub processed: String, 
    pub length: usesize,
}

#[wasm_bindgen]
pub fn process_input(input: &str) -> JsValue { 
    let result = ResultObject { 
        processed: input.to_uppercase(), 
        length: input.len(), 
    }; 
    JsValue::from_serde(&result).unwrap()
}

What this code does:
  1. takes an input string, transforms it into uppercase and returns a JSON object with the result. 
  2. exports the function process_input to be called by JavaScript.

3. Compile for WebAssembly with wasm-pack

cd wasm_demo
wasm-pack build --target web

4. Loading and using in HTML/JavaScript

Copies the contents of the pkg/ folder generated by wasm-pack to a directory accessible by HTML.

Create an HTML page - e.g. index.html:

<!DOCTYPE html>
<html lang="en">
    <head> 
        <meta charset="UTF-8"> 
        <title>Wasm Demo</title> 
        <script type="module"> 
            import init, { process_input } from './pkg/wasm_demo.js'; 

            async function run() { 
                await init(); 
                const result = process_input("hi wasm!"); 
                console.log("Result:", result); 
            } 

            run(); 
        </script>
    </head>
    <body> 
        <h1>WebAssembly Demo</h1>
    </body>
</html>

By opening index.html in a compatible browser, you will see something like this in the console:

Expected output to console:

Result: { processed: "HI WASM!", length: 8 }

Wait a moment: but what is the difference between the module.wasm file seen at the beginning and the wasm_demo.js file of the previous example?

The difference between module.wasm and wasm_demo.js (or any .js file generated by wasm-pack) is fundamental to understand how the integration between WebAssembly and JavaScript works. Let's describe them clearly:

1. module.wasm – The WebAssembly binary module

This is the real compiled module. Contains portable machine code generated by Rust (or C/C++) in binary .wasm format.

  • This is what the browser runs in the sandbox.

  • It does not contain any loading logic or JS binding.

  • You must instantiate it manually in JavaScript using the WebAssembly.instantiate APIs.

Minimal direct loading example:

const response = await fetch('module.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes);
console.log(instance.exports.myFunction());

2. wasm_demo.js – The JavaScript wrapper generated by wasm-pack

This file is automatically generated by wasm-pack, a command-line tool developed by the Rust community (under the rustwasm) that simplifies the process of compiling Rust projects in WebAssembly for use on the web, especially with JavaScript.

wasm-pack serves as a bridge between WebAssembly and the JavaScript world.

Example:

import init, { process_input } from './pkg/wasm_demo.js';

await init(); // initialize the .wasm module
const result = process_input("hi wasm!");
console.log(result);

When you compile with wasm-pack, you get two main files:

  • wasm_demo_bg.wasm: the actual WebAssembly module.
  • wasm_demo.js: a JavaScript wrapper generated by wasm-pack that:
    • Loads the .wasm module.
    • Handles conversions between Rust and JavaScript types.
    • Exposes functions idiomatically for JS.
Note: wasm_demo_bg.wasm is the real name generated by wasm-pack, while module.wasm is a generic example used in tutorials/manuals.

Difference summary

File Content Main role
wasm_demo_bg.wasm Wasm binary compiled by Rust Run by browser (core)
wasm_demo.js JavaScript Wrapper JS ↔ Wasm link (typical management)


When to use one or the other?

  • module.wasm → if you are working manually with WebAssembly using only the standard WebAssembly API in JS and want maximum control (requires manual coding and does not support complex types without extra work).

  • wasm_demo.js + .wasm → if you want to simplify your life and use functions with strings or JSON. For example if you use Rust + wasm-pack + wasm-bindgen, which is the modern and most productive method.


Manually loading a .wasm module [for curious and academics]

If at this point you are curious to know what it would be like to manually load a wasm module in JavaScript without going through wasm-pack,or you simply want to delve deeper into the low-level operation, then this paragraph is ideal to understand step-by-step how the integration between Wasm and JS.

1. Simplified Wasm module in Rust

For the purposes of this tutorial (and to prevent this introductory Wasm article from being infinite), we will avoid complex functions and not use wasm-bindgen (this is to make manual loading easier to do). We will write a simple function that returns a number.

src/lib.rs (without wasm-bindgen)

#[no_mangle]
pub extern "C" fn square(x: i32) -> i32 {
    x * x
}

Note:

  • #[no_mangle] is used to prevent the compiler from changing the name of the function.

  • extern "C" makes the function compatible with the call from external languages ​​(C / JS).

2. Compiling to .wasm manually

Compile with cargo and wasm32-unknown-unknown:

rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown

The .wasm file can be found here:

target/wasm32-unknown-unknown/release/<project_name>.wasm

Copy it to a folder accessible from your web project.


3. HTML + JS without wrappers

index.html

<html>
    <head> 
        <meta charset="UTF-8"></meta> 
        <title>Manual Wasm</title> 
        <script> 
            async function loadWasm() { 
                const response = await fetch('module.wasm'); 
                const bytes = await response.arrayBuffer(); 
                const { instance } = await WebAssembly.instantiate(bytes); 

                const result = instance.exports.square(7); 
                console.log("The square of 7 is:", result); 
            } 

            loadWasm(); 
        </script>
    </head>
    <body> 
        <h1>WebAssembly without wrapper</h1>
    </body>
</html>

Output to console:

Thesquare of 7 is: 49

Main differences compared to the wasm-pack

wrapper
Manual loading With wasm-pack (wasm_demo.js)
You need to handle everything at a low level Exposes convenient functions and conversions
You can't use complex types (strings, objects) without extra work Supports strings, JSON, objects via wasm-bindgen
Requires #[no_mangle] and extern "C" Use idiomatic Rust macros
Best suited for minimalistic modules Best suited for applications modern

Browser Support

WebAssembly is supported in the main browsers starting from the following versions:

Browser Wasm support from Version
Google Chrome March 2017 57
Mozilla Firefox March 2017 52
Microsoft Edge October 2017 16
Apple Safari September 2017 11
Opera March 2017 44

All modern mobile browsers based on WebKit, Blink or Gecko (such as Chrome for Android and Safari for iOS) support Wasm.

You can also check it out on Can I Use.


WebAssembly Extensions and Future

WebAssembly continues to evolve, with advanced features being standardized:

  • WASI (WebAssembly System Interface): Server-side execution.

  • Garbage Collection: for memory-managed languages ​​(e.g. Kotlin, C#).

  • Threading and SIMD: for parallel performance and vector operations.

  • Exception Handling: better error handling.


Some use cases real:

  • Gaming (Unity via WebGL + Wasm)
  • Desktop app (e.g. Figma uses WebAssembly)
  • Client-side encryption
  • Video/audio processing directly in JS

Official resources and tutorials

Documentation:

Tools and environments:

Practical tutorials:


Conclusion

WebAssembly represents one of the most important evolutions of the modern web. It brings high-performance compiled code to the browser in a secure and versatile way. Knowing how to use it, even just to extend the capabilities of JavaScript, is a valuable skill for frontend and backend developers. And thanks to tools like wasm-pack, entering the world of Wasm is now much more accessible.



Follow me #techelopment

Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
/>telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment