Top Related Projects
A TypeScript-like language for WebAssembly.
The WebAssembly Binary Toolkit
Emscripten: An LLVM-to-WebAssembly Compiler
Facilitating high-level interactions between Wasm modules and JavaScript
The WebAssembly Pre-Initializer
Quick Overview
Wasmer-js is a JavaScript library that allows running WebAssembly modules in Node.js and the browser. It provides a high-level API for loading and executing WebAssembly modules, making it easier to integrate WebAssembly into JavaScript applications.
Pros
- Cross-platform compatibility (works in both Node.js and browsers)
- Easy-to-use API for loading and running WebAssembly modules
- Supports various WebAssembly features, including WASI (WebAssembly System Interface)
- Actively maintained and part of the larger Wasmer ecosystem
Cons
- Performance overhead compared to native WebAssembly implementations
- Limited documentation and examples for advanced use cases
- Dependency on the Wasmer runtime, which may increase bundle size
- Potential compatibility issues with some WebAssembly modules
Code Examples
- Loading and running a WebAssembly module:
import { WASI } from "@wasmer/wasi";
import { WasmFs } from "@wasmer/wasmfs";
const wasmFs = new WasmFs();
const wasi = new WASI({
args: [],
env: {},
bindings: {
...WASI.defaultBindings,
fs: wasmFs.fs
}
});
const module = await WebAssembly.compileStreaming(fetch("module.wasm"));
const instance = await WebAssembly.instantiate(module, {
wasi_snapshot_preview1: wasi.wasiImport
});
wasi.start(instance);
- Calling a WebAssembly function from JavaScript:
import { WASI } from "@wasmer/wasi";
const wasi = new WASI({});
const module = await WebAssembly.compileStreaming(fetch("math.wasm"));
const instance = await WebAssembly.instantiate(module, {
wasi_snapshot_preview1: wasi.wasiImport
});
const { add } = instance.exports;
console.log(add(5, 3)); // Output: 8
- Reading file system contents after WASI execution:
import { WASI } from "@wasmer/wasi";
import { WasmFs } from "@wasmer/wasmfs";
const wasmFs = new WasmFs();
const wasi = new WASI({
bindings: {
...WASI.defaultBindings,
fs: wasmFs.fs
}
});
// ... load and run WASI module ...
const contents = wasmFs.fs.readFileSync("/output.txt", "utf8");
console.log(contents);
Getting Started
To use wasmer-js in your project:
-
Install the required packages:
npm install @wasmer/wasi @wasmer/wasmfs
-
Import the necessary modules in your JavaScript file:
import { WASI } from "@wasmer/wasi"; import { WasmFs } from "@wasmer/wasmfs";
-
Load and run a WebAssembly module:
const wasi = new WASI({}); const module = await WebAssembly.compileStreaming(fetch("module.wasm")); const instance = await WebAssembly.instantiate(module, { wasi_snapshot_preview1: wasi.wasiImport }); wasi.start(instance);
For more advanced usage and configuration options, refer to the official documentation and examples in the wasmer-js repository.
Competitor Comparisons
A TypeScript-like language for WebAssembly.
Pros of AssemblyScript
- Provides a TypeScript-like syntax for writing WebAssembly, making it more accessible to JavaScript developers
- Offers a comprehensive standard library and ecosystem of tools for WebAssembly development
- Supports direct compilation to WebAssembly without requiring a separate runtime
Cons of AssemblyScript
- Limited to WebAssembly as the target, while Wasmer-js supports multiple backends
- May have performance overhead compared to lower-level languages like C or Rust
- Lacks some advanced features available in more mature programming languages
Code Comparison
AssemblyScript:
export function add(a: i32, b: i32): i32 {
return a + b;
}
Wasmer-js (using JavaScript to interact with WebAssembly):
const instance = await WebAssembly.instantiate(wasmModule, importObject);
const result = instance.exports.add(5, 3);
Note: The code comparison is not directly equivalent, as Wasmer-js is primarily a runtime for WebAssembly modules, while AssemblyScript is a language for writing WebAssembly modules. The Wasmer-js example shows how to interact with a WebAssembly module, which could have been compiled from AssemblyScript or any other language targeting WebAssembly.
The WebAssembly Binary Toolkit
Pros of wabt
- More comprehensive toolset for working with WebAssembly binary format
- Longer development history and wider community adoption
- Supports multiple programming languages (C++, Python, JavaScript)
Cons of wabt
- Primarily focused on low-level WebAssembly operations
- Steeper learning curve for developers new to WebAssembly
- Less emphasis on high-level runtime features
Code Comparison
wabt (C++):
#include "src/binary-reader.h"
#include "src/error-formatter.h"
std::unique_ptr<Module> ReadModule(const std::string& filename,
Errors* errors) {
return ReadModule(filename, READ_BINARY, nullptr, nullptr, errors);
}
wasmer-js (JavaScript):
import { WASI } from '@wasmer/wasi';
import { WasmFs } from '@wasmer/wasmfs';
const wasmFs = new WasmFs();
const wasi = new WASI({
args: [],
env: {},
bindings: {
...WASI.defaultBindings,
fs: wasmFs.fs
}
});
The code snippets demonstrate the different focus areas of the two projects. wabt provides low-level utilities for reading and manipulating WebAssembly modules, while wasmer-js offers a higher-level API for running WebAssembly modules with WASI support and filesystem emulation.
Emscripten: An LLVM-to-WebAssembly Compiler
Pros of Emscripten
- Mature and widely adopted toolchain for compiling C/C++ to WebAssembly
- Extensive documentation and community support
- Provides a complete runtime environment, including system libraries
Cons of Emscripten
- Larger output size due to included runtime and libraries
- Steeper learning curve for developers new to WebAssembly
- Can be slower for certain use cases compared to more lightweight alternatives
Code Comparison
Emscripten:
#include <emscripten.h>
#include <stdio.h>
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
Wasmer-js:
import { WASI } from '@wasmer/wasi';
import { WasmFs } from '@wasmer/wasmfs';
const wasmFs = new WasmFs();
const wasi = new WASI({
args: [],
env: {},
bindings: {
...WASI.defaultBindings,
fs: wasmFs.fs
}
});
Emscripten focuses on compiling C/C++ to WebAssembly with a full runtime, while Wasmer-js provides a more lightweight approach for running and interacting with WebAssembly modules in JavaScript environments. Emscripten offers a more comprehensive solution but may result in larger output sizes, whereas Wasmer-js provides greater flexibility and potentially smaller bundle sizes for specific use cases.
Facilitating high-level interactions between Wasm modules and JavaScript
Pros of wasm-bindgen
- More mature and widely adopted in the Rust ecosystem
- Tighter integration with Rust's type system and toolchain
- Supports generating TypeScript definitions for better type safety
Cons of wasm-bindgen
- Limited to Rust-to-WebAssembly compilation
- Steeper learning curve for developers new to Rust
- Less flexibility for runtime WebAssembly execution
Code Comparison
wasm-bindgen:
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
wasmer-js:
const instance = await WebAssembly.instantiate(wasmBytes, imports);
const result = instance.exports.add(5, 3);
wasm-bindgen focuses on compile-time bindings and type generation, while wasmer-js provides a runtime-oriented approach for executing WebAssembly modules. wasm-bindgen is more tightly integrated with Rust, offering seamless interop between Rust and JavaScript. wasmer-js, on the other hand, provides a more language-agnostic solution for running WebAssembly modules in JavaScript environments, with support for various WebAssembly features and optimizations.
The WebAssembly Pre-Initializer
Pros of Wizer
- Focuses on WebAssembly module initialization, potentially offering more specialized optimization
- Part of the Bytecode Alliance, which may provide broader ecosystem support and integration
- Designed for ahead-of-time initialization, which can improve runtime performance
Cons of Wizer
- More limited in scope compared to Wasmer-js's broader WebAssembly runtime capabilities
- May require additional tools or setup for full WebAssembly execution in JavaScript environments
- Less mature project with potentially fewer community resources and examples
Code Comparison
Wizer (initialization focus):
use wizer::Wizer;
let wizer = Wizer::new();
let initialized_wasm = wizer.run(wasm_bytes)?;
Wasmer-js (runtime execution):
import { WASI } from '@wasmer/wasi';
import { WasmFs } from '@wasmer/wasmfs';
const wasmFs = new WasmFs();
const wasi = new WASI({
args: [], env: {}, bindings: { ...wasmFs.bindings }
});
const instance = await WebAssembly.instantiate(wasmBytes, {
wasi_snapshot_preview1: wasi.wasiImport
});
This comparison highlights the different focuses of the two projects. Wizer concentrates on module initialization, while Wasmer-js provides a more comprehensive WebAssembly runtime environment in JavaScript. The code snippets demonstrate their distinct approaches to working with WebAssembly modules.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
The Wasmer JavaScript SDK
Javascript library for running Wasmer packages at ease, including WASI and WASIX modules.
Getting Started
Install from NPM
For instaling @wasmer/sdk
, run this command in your shell:
npm install --save @wasmer/sdk
You can now run packages from the Wasmer registry:
import { init, Wasmer } from "@wasmer/sdk";
await init();
const pkg = await Wasmer.fromRegistry("python/python");
const instance = await pkg.entrypoint.run({
args: ["-c", "print('Hello, World!')"],
});
const { code, stdout } = await instance.wait();
console.log(`Python exited with ${code}: ${stdout}`);
Use with a <script>
tag (without bundler)
It is possible to avoid needing to use a bundler by importing @wasmer/sdk
from your script tag in unpkg.
<script defer type="module">
import { init, Wasmer } from "https://unpkg.com/@wasmer/sdk@latest/dist/index.mjs";
async function runPython() {
await init();
const packageName = "python/python";
const pkg = await Wasmer.fromRegistry(packageName);
const instance = await pkg.entrypoint.run({
args: ["-c", "print('Hello, World!')"],
});
const { code, stdout } = await instance.wait();
console.log(`Python exited with ${code}: ${stdout}`);
}
runPython();
</script>
Using a custom Wasm file
By default, init
will load the Wasmer SDK WebAssembly file from the package.
If you want to customize this behavior you can pass a custom url to the init, so the the wasm file
of the Wasmer SDK can ve served by your HTTP server instead:
import { init, Wasmer } from "@wasmer/sdk";
import wasmerSDKModule from "@wasmer/sdk/wasm?url";
await init({ module: wasmUrl }); // This inits the SDK with a custom URL
Using a JS with the Wasm bundled
You can also load Wasmer-JS with a js file with the Wasmer SDK WebAssembly file bundled into it (using base64 encoding),
so no extra requests are required. If that's your use case, you can simply import @wasmer/sdk/wasm-inline
:
import { init, Wasmer } from "@wasmer/sdk";
import wasmerSDKModule from "@wasmer/sdk/wasm-inline";
await init({ module: wasmerSDKModule }); // This uses the inline wasmer SDK version
Cross-Origin Isolation
Browsers have implemented security measures to mitigate the Spectre and Meltdown vulnerabilities.
These measures restrict the sharing of `SharedArrayBuffer`` objects with Web Workers unless the execution context is deemed secure.
The @wasmer/sdk
package uses a threadpool built on Web Workers and requires
sharing the same SharedArrayBuffer
across multiple workers to enable WASIX
threads to access the same address space. This requirement is crucial even for
running single-threaded WASIX programs because the SDK internals rely on
SharedArrayBuffer
for communication with Web Workers.
To avoid Cross-Origin Isolation issues, make sure any web pages using
@wasmer/sdk
are served over HTTPS and have the following headers set:
"Cross-Origin-Opener-Policy": "same-origin"
"Cross-Origin-Embedder-Policy": "require-corp"
See the SharedArrayBuffer
and Cross-Origin Isolation section under
the Troubleshooting Common Problems docs for more.
Creating packages
Users can create packages providing a manifest and using the Wasmer.createPackage()
function:
import { init, Wasmer } from "@wasmer/sdk";
await init({ token: "YOUR_TOKEN" });
const manifest = {
command: [
{
module: "wasmer/python:python",
name: "hello",
runner: "wasi",
annotations: {
wasi: {
"main-args": [
"-c",
"print('Hello, js!'); ",
],
},
},
},
],
dependencies: {
"wasmer/python": "3.12.9+build.9",
}
};
let pkg = await Wasmer.createPackage(manifest);
let instance = await pkg.commands["hello"].run();
const output = await instance.wait();
console.log(output)
Publishing packages
User can publish packages following the same flow used to create a package and then calling the Wasmer.publishPackage()
function:
import { init, Wasmer } from "@wasmer/sdk";
await init({ token: "YOUR_TOKEN" });
const manifest = {
package: {
name: "<YOUR_NAME>/<YOUR_PACKAGE_NAME>"
}
command: [
{
module: "wasmer/python:python",
name: "hello",
runner: "wasi",
annotations: {
wasi: {
"main-args": [
"-c",
"print('Hello, js!'); ",
],
},
},
},
],
dependencies: {
"wasmer/python": "3.12.9+build.9",
}
};
let pkg = await Wasmer.createPackage(manifest);
await Wasmer.publishPackage(pkg);
Trying to publish packages without a package.name
property in the manifest will result in a failure.
Deploying apps
User can deploy apps by providing an app configuration and calling the Wasmer.deployApp()
function:
import { init, Wasmer } from "@wasmer/sdk";
// Get your token here: https://wasmer.io/settings/access-tokens
await init({ token: "YOUR_TOKEN" });
let appConfig = {
name: "<YOUR_APP_NAME>",
owner: "<YOUR_NAME>",
package: "wasmer/hello"
default: true,
};
await Wasmer.deployApp(appConfig);
Users can also publish apps with their own packages simply providing the package in the config:
import wasmUrl from "@wasmer/sdk";
// Get your token here: https://wasmer.io/settings/access-tokens
await init({token: "YOUR_TOKEN"});
const echo_server_index = `
async function handler(request) {
const out = JSON.stringify({
env: process.env,
});
return new Response(out, {
headers: { "content-type": "application/json" },
});
}
addEventListener("fetch", (fetchEvent) => {
fetchEvent.respondWith(handler(fetchEvent.request));
});
`;
const manifest =
{
"command": [
{
"module": "wasmer/winterjs:winterjs",
"name": "script",
"runner": "https://webc.org/runner/wasi",
"annotations": {
"wasi": {
"env": [
"JS_PATH=/src/index.js"
],
"main-args": [
"/src/index.js"
]
}
}
}
],
"dependencies": {
"wasmer/winterjs": "1.2.0"
},
"fs": {
"/src": {
"index.js": echo_server_index
}
},
};
let wasmerPackage = await Wasmer.createPackage(manifest);
let appConfig = {
name: "my-echo-env-app",
owner: "edoardo",
package: wasmerPackage,
default: true,
};
let res = await Wasmer.deployApp(appConfig);
console.log(res.url)
Features
The Wasmer SDK Javascript Package supports:
- WASI support
- Environment variables
- FileSystem access
- Command-line arguments
- Stdio
- WASIX support
- Multi-threading
- Spawning sub-processes
- Networking (on the works)
- Mounting directories inside the WASIX instance
- Running packages from the Wasmer Registry
- Platforms
- Browser
- NodeJS
- Deno
- Registry API
- Create a package
- Publish a package
- Deploy an application
License
The entire project is under the MIT License. Please read the
LICENSE
file.
Top Related Projects
A TypeScript-like language for WebAssembly.
The WebAssembly Binary Toolkit
Emscripten: An LLVM-to-WebAssembly Compiler
Facilitating high-level interactions between Wasm modules and JavaScript
The WebAssembly Pre-Initializer
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot