Introduction to WebAssembly and its Role in Node.js
\n\nWebAssembly (WASM) is a low-level binary instruction format that runs in a virtual machine with near-native performance. In the Node.js ecosystem, WebAssembly opens new horizons: it allows executing code written in C, C++, Rust, or Go directly in the server environment. This is especially relevant for tasks requiring high performance: image processing, cryptography, data parsing, working with large arrays of numbers.
\n\nIn this article, we will cover the complete workflow of working with WebAssembly in Node.js: from compiling source code to integrating the finished module into a JavaScript application.
\n\nBasic Concepts and Environment Setup
\n\nWhat You Need to Know Before Starting
\nA WebAssembly module is a binary file with the .wasm extension. It does not have direct access to the DOM or file system — all interaction occurs through "imported functions" that you pass from JavaScript. In Node.js, this limitation is removed using special wrappers.
Installing Tools
\nTo compile code to WASM, we need the Emscripten SDK. Installation on Linux/macOS:
\ngit clone https://github.com/emscripten-core/emsdk.git\ncd emsdk\n./emsdk install latest\n./emsdk activate latest\nsource ./emsdk_env.sh\n\nFor Rust projects, use wasm-pack:
npm install -g wasm-pack\n\nCreating and Compiling Your First WASM Module
\n\nExample in C — Addition Function
\nLet's create a simple function in C that adds two numbers:
\n// math.c\n#include <emscripten.h>\n\nEMSCRIPTEN_KEEPALIVE\nint add(int a, int b) {\n return a + b;\n}\n\nEMSCRIPTEN_KEEPALIVE\nint multiply(int a, int b) {\n return a * b;\n}\n\nCompile to WASM using Emscripten:
\nemcc math.c -o math.js -s EXPORTED_FUNCTIONS="['_add', '_multiply']" -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME="createMathModule"\n\nThe output produces two files: math.wasm and math.js — a wrapper for loading.
Loading the Module in Node.js
\nNow use the module in JavaScript:
\n// index.js\nconst createMathModule = require('./math.js');\n\ncreateMathModule().then(module => {\n const add = module._add;\n const multiply = module._multiply;\n\n console.log('5 + 3 =', add(5, 3)); // 8\n console.log('4 * 7 =', multiply(4, 7)); // 28\n});\n\nRun it:
\nnode index.js\n\nWorking with Memory and Complex Data Types
\n\nPassing Strings and Arrays
\nWASM only operates with numbers. To pass strings or arrays, you need to allocate memory in the module's linear memory. Let's look at an example in C that accepts a string and returns its length:
\n// string_ops.c\n#include <string.h>\n#include <emscripten.h>\n\nEMSCRIPTEN_KEEPALIVE\nint string_length(char* str) {\n return strlen(str);\n}\n\nEMSCRIPTEN_KEEPALIVE\nvoid to_upper(char* str) {\n for (int i = 0; str[i]; i++) {\n if (str[i] >= 'a' && str[i] <= 'z') {\n str[i] -= 32;\n }\n }\n}\n\nCompile it:
\nemcc string_ops.c -o string_ops.js -s EXPORTED_FUNCTIONS="['_string_length', '_to_upper']" -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME="createStringModule"\n\nJavaScript code for working with memory:
\nconst createStringModule = require('./string_ops.js');\n\ncreateStringModule().then(module => {\n const { _string_length, _to_upper, heap } = module;\n \n // Allocate memory for the string\n const input = "hello world";\n const ptr = module._malloc(input.length + 1);\n \n // Copy the string into WASM memory\n for (let i = 0; i < input.length; i++) {\n heap[i + ptr] = input.charCodeAt(i);\n }\n heap[ptr + input.len