Fundamentals 18 min read

WebAssembly Overview, Setup, and Usage with Emscripten, C/C++, and Rust

This article explains the evolution of JavaScript performance, introduces WebAssembly concepts and browser support, provides step‑by‑step installation of Emscripten, WABT, and related tools on macOS, demonstrates WebAssembly APIs such as validate, Module, compile, Instance, Memory and Table, and shows practical examples of compiling and invoking C/C++ and Rust code from JavaScript.

JD Retail Technology
JD Retail Technology
JD Retail Technology
WebAssembly Overview, Setup, and Usage with Emscripten, C/C++, and Rust

JavaScript performance dramatically improved after browsers introduced Just‑In‑Time (JIT) compilation around 2008, making code run 20–50 times faster and enabling new use cases like server‑side Node.js.

WebAssembly (".wasm") is a portable binary format designed for efficient loading and execution in browsers, offering significant speed advantages over asm.js and allowing low‑level languages such as C and C++ to run on the web.

All major browsers now support WebAssembly: Safari 11, Edge 16, Firefox 52, and Chrome 57.

Development Preparation (macOS)

Install required tools:

brew install cmake
brew install python

Then install Emscripten:

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install --build=Release sdk-64bit
./emsdk activate --global --build=Release
export PATH="/Users/liuyan/Work/emsdk:/Users/liuyan/Work/emsdk/clang/fastcomp/build_incoming_64/bin:/Users/liuyan/Work/emsdk/node/8.9.1_64bit/bin:/Users/liuyan/Work/emsdk/emscripten/incoming:/Users/liuyan/Work/emsdk/binaryen/master_64bit_binaryen/bin:$PATH"
export EMSDK="/Users/liuyan/Work/emsdk"
export EM_CONFIG="/Users/liuyan/.emscripten"
source ~/.bash_profile
Install WABT (WebAssembly Binary Toolkit) to convert .wast to .wasm:
git clone https://github.com/WebAssembly/wabt.git
cd wabt
make install -release
Enable WebAssembly in browsers (Chrome: chrome://flags/#enable-webassembly, Firefox: about:config → javascript.options.wasm = true).
WebAssembly API
WebAssembly.validate()
checks whether a binary buffer is a valid module and returns a boolean.
WebAssembly.validate(bufferSource);
WebAssembly.Module
synchronously compiles a binary module; asynchronous compilation is preferred via
WebAssembly.compile()
or
WebAssembly.instantiate()
.
var myModule = new WebAssembly.Module(bufferSource);
WebAssembly.Instance
creates an executable instance of a module, exposing exported functions to JavaScript.
var myInstance = new WebAssembly.Instance(module, importObject);
WebAssembly.instantiate()
compiles and instantiates a module in one step, returning a promise that resolves to an instance.
WebAssembly.instantiate(bufferSource, importObject).then(({instance}) => { /* use instance.exports */ });
WebAssembly.Memory
provides linear memory for a module; it can be created before instantiation and passed via the import object.
var myMemory = new WebAssembly.Memory({initial:256, maximum:256});
WebAssembly.Table
creates a function table for indirect calls.
var myTable = new WebAssembly.Table({element:'anyfunc', initial:0, maximum:0});
Using WebAssembly
WebAssembly modules are loaded with
fetch
, converted to an
ArrayBuffer
, then compiled/instantiated. Example loader:
function loadWebAssembly(path, imports={}) {
  return fetch(path)
    .then(res => res.arrayBuffer())
    .then(buffer => WebAssembly.compile(buffer))
    .then(module => {
      imports.env = imports.env || {};
      imports.env.memory = new WebAssembly.Memory({initial:256, maximum:256});
      imports.env.table = new WebAssembly.Table({element:'anyfunc', initial:0, maximum:0});
      return new WebAssembly.Instance(module, imports);
    });
}
After loading, exported functions can be called directly:
loadWebAssembly('math.wasm').then(instance => {
  const {add, square} = instance.exports;
  console.log('2 + 4 =', add(2,4));
  console.log('3^2 =', square(3));
});
Compiling C/C++ to WebAssembly with Emscripten
Example
hello.c
:
#include
int main(){ printf("Hello World\n"); return 0; }
Compile to HTML + wasm:
emcc hello.c -s WASM=1 -o hello.html
To export a custom function, use
EMSCRIPTEN_KEEPALIVE
and enable
EXTRA_EXPORTED_RUNTIME_METHODS=["ccall"]
:
int EMSCRIPTEN_KEEPALIVE myFunction(int argc, char** argv){ printf("MyFunction Called\n"); }

emcc -o hello2.html hello2.c -O3 -s WASM=1 -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall"]' --shell-file shell_minimal.html
Call from JavaScript:
var result = Module.ccall('myFunction', 'number', ['number'], [42]);
Compiling Rust to WebAssembly
Install Rustup, add the
wasm32-unknown-unknown
target, and use
cargo
to build a library as a
cdylib
. Example
Cargo.toml
snippet:
[lib]
path = "src/lib.rs"
crate-type = ["cdylib"]
Build with:
cargo +nightly build --target wasm32-unknown-unknown --release
Optionally run
wasm-gc
to shrink the output.
Performance Advantages of WebAssembly
WebAssembly files are smaller and faster to download, require no parsing to abstract syntax trees, and are decoded directly to binary code, eliminating the heavy parsing and JIT compilation stages of JavaScript. Because types are known ahead of time, no re‑optimization is needed, and execution can be close to native speed, often yielding 10‑800% performance gains.
Future Features
Direct DOM manipulation from WebAssembly.
SIMD support for parallel data processing.
Integration as ES6 modules, allowing
import
of WebAssembly files.
PerformanceJavaScriptRustWebAssemblycEmscripten
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.