npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wasmati

v0.2.4

Published

Write low-level WebAssembly, from JavaScript

Downloads

191

Readme

wasmati 🍚   npm version

Write low-level WebAssembly, from JavaScript

wasmati is a TS library that lets you create Wasm modules by writing out their instructions.

  • 🥷 You want to create low-level, hand-optimized Wasm libraries? wasmati is the tool to do so effectively.
  • 🚀 You want to sprinkle some Wasm in your JS app, to speed up critical parts? wasmati gives you a JS-native way to achieve that.
  • ⚠️ You want to compile Wasm modules from a high-level language, like Rust or C? wasmati is not for you.
npm i wasmati
// example.ts
import { i64, func, Module } from "wasmati";

const myMultiply = func({ in: [i64, i64], out: [i64] }, ([x, y]) => {
  i64.mul(x, y);
});

let module = Module({ exports: { myMultiply } });
let { instance } = await module.instantiate();

let result = instance.exports.myMultiply(5n, 20n);
console.log({ result });
$ node --experimental-strip-types example.ts
{ result: 100n }

Features

  • Works in all modern browsers, node and deno

  • Parity with WebAssembly. The API directly corresponds to Wasm opcodes, like i32.add etc. All opcodes and language features of the latest WebAssembly spec (2.0) are supported.
    In addition, wasmati supports the following extensions which are not part of the spec at the time of writing:

  • Readability. Wasm code looks imperative - like writing WAT by hand, just with better DX:

const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  local.get(x);
  local.get(y);
  i32.add();
  i32.const(2);
  i32.shl();
  call(otherFunction);
});
  • Optional syntax sugar to reduce boilerplate assembly like local.get and i32.const
const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  i32.add(x, y); // local.get(x), local.get(y) are filled in
  i32.shl($, 2); // $ is the top of the stack; i32.const(2) is filled in
  call(otherFunction);
});

// or also

const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  let z = i32.add(x, y);
  call(otherFunction, [i32.shl(z, 2)]);
});
  • Type-safe. Example: Local variables are typed; instructions know their input types:
const myFunction = func(
  { in: [i32, i32], locals: [i64], out: [i32] },
  ([x, y], [u]) => {
    i32.add(x, u); // type error: Type '"i64"' is not assignable to type '"i32"'.
  }
);
  • Great debugging DX. Stack traces point to the exact line in your code where an invalid opcode is called:
Error: i32.add: Expected i32 on the stack, got i64.
    ...
    at file:///home/gregor/code/wasmati/examples/example.ts:16:9
  • Easy construction of modules. Just declare exports; dependencies and imports are collected for you. Nothing ends up in the module which isn't needed by any of its exports or its start function.
let mem = memory({ min: 10 });

let module = Module({ exports: { myFunction, mem } });
let instance = await module.instantiate();
  • Excellent type inference. Example: Exported function types are inferred from func definitions:
instance.exports.myFunction;
//                 ^ (arg_0: number, arg_1: number) => number
  • Atomic import declaration. Imports are declared as types along with their JS values. Abstracts away the global "import object" that is separate from "import declaration".
const consoleLog = importFunc({ in: [i32], out: [] }, (x) =>
  console.log("logging from wasm:", x)
);

const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  call(consoleLog, [x]);
  i32.add(x, y);
});
  • Great composability and IO
    • Internal representation of modules / funcs / etc is a readable JSON object
    • Convert to/from Wasm bytecode with module.toBytes(), Module.fromBytes(bytes)

Features that aren't implemented yet

PRs welcome!

  • Wasmati build. We want to add an optional build step which takes as input a file that exports your Module, and compiles it to a file which doesn't depend on wasmati at runtime. Instead, it hard-codes the Wasm bytecode as base64 string, correctly imports all dependencies (imports) for the instantiation like the original file did, instantiates the module (top-level await) and exports the module's exports.
// example.ts
let module = Module({ exports: { myFunction, mem } });

export { module as default };
import { myFunction } from "./example.wasm.js"; // example.wasm.js does not depend on wasmati at runtime
  • Experimental Wasm opcodes. We want to support opcodes from recently standardized or in-progress feature proposals (like this one) which haven't yet made it to the spec. The eventual goal is to support proposals as soon as they are implemented in at least one JS engine.

  • Custom module sections. We want to support creation and parsing of "custom sections" like the name section

Some ideas that are a bit further out:

  • Decompiler: take any Wasm file and create wasmati TS code from it -- to modify it, debug it etc
  • Source maps, so you can look at the culprit JS code when Wasm throws an error
  • Optional JS interpreter which can take DSL code and execute it in JS
    • could enable even more flexible debugging -- inspect the stack, global/local scope etc