• Stars
    star
    244
  • Rank 165,885 (Top 4 %)
  • Language WebAssembly
  • License
    MIT License
  • Created about 5 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Isomorphic library to handle passing high-level data structures between AssemblyScript and JavaScript 🤝🚀

as-bind

Build Status npm bundle size (minified) npm npm version GitHub

Isomorphic library to handle passing high-level data structures between AssemblyScript and JavaScript. 🤝🚀

Markdown Parser Demo

Asbind Markdown Parser Demo Gif

Table of Contents

Features

  • The library is isomorphic. Meaning it supports both the Browser, and Node! And has ESM, AMD, CommonJS, and IIFE bundles! 🌐
  • Wraps around the AssemblyScript Loader. The loader handles all the heavy-lifting of passing data into WebAssembly linear memory. 💪
  • Wraps around imported JavaScript functions, and exported AssemblyScript functions of the AssemblyScript Wasm Module. This allows high-level data types to be passed directly to exported AssemblyScript functions! 🤯
  • Moves a lot of work to compile-time using AssemblyScript Transforms and completely avoids module-specific “glue code”. 🏃
  • Installable from package managers (npm), with a modern JavaScript API syntax. 📦
  • The library is < 4KB (minified and gzip'd), including the AssemblyScript Loader ! 🌲
  • This library is currently (as of January, 2020) the wasm-bindgen of AssemblyScript. 😀

Installation

You can install as-bind in your project by running the following:

npm install --save as-bind

Quick Start

1. Compiling your Assemblyscript

To enable as-bind for your AssemblyScript Wasm modules, add the as-bind transform when compiling your module:

asc your-entryfile.ts --exportRuntime --transform as-bind [...other cli options...]

The things to notice are:

  • --transform as-bind - This is the as-bind transform that runs at compile time. It embeds all the required type information into the WebAssembly Module.
  • --exportRuntime - This is required for the AssemblyScript Loader to work properly. It exposes functions on the module to allocate memory from JavaScript.

For optional testing purposes , let's export an example function we can try in your-entryfile.ts:

export function myExportedFunctionThatTakesAString(value: string): string {
  return "AsBind: " + value;
}

2. In your Javascript

For browser JavaScript. We can do the following:

// If you are using a Javascript bundler, use the ESM bundle with import syntax
import * as AsBind from "as-bind";

// If you are not using a bundler add a <script> tag to your HTML
// Where the `src` points to the iife bundle (as-bind.iife.js), for example: https://unpkg.com/as-bind
// Then, INSTEAD of using the import syntax, do: `const { AsBind } = AsBindIIFE;`

const wasm = fetch("./path-to-my-wasm.wasm");

const asyncTask = async () => {
  const asBindInstance = await AsBind.instantiate(wasm);

  // You can now use your wasm / as-bind instance!
  const response = asBindInstance.exports.myExportedFunctionThatTakesAString(
    "Hello World!"
  );
  console.log(response); // AsBind: Hello World!
};
asyncTask();

For Node JavaScript, we would use the CommonJS bundle by doing the following:

// We need to import the direct as-bind.cjs.js for Node applications.
// This is because the default "main" key in the `package.json`,
// is the as-bind transform script
const AsBind = require("as-bind/dist/as-bind.cjs.js");

const fs = require("fs");

const wasm = fs.readFileSync("./path-to-my-wasm.wasm");

const asyncTask = async () => {
  const asBindInstance = await AsBind.instantiate(wasm);

  // You can now use your wasm / as-bind instance!
  const response = asBindInstance.exports.myExportedFunctionThatTakesAString(
    "Hello World!"
  );
  console.log(response); // AsBind: Hello World!
};
asyncTask();

Additional Examples

Passing a high-level type to a an exported function, and returning a high-level type

See the Quick Start

Passing a high-level type to an imported function

In this example, we will implement a console.log that we can call from AssemblyScript!

AssemblyScript

Inside of myWasmFileName.ts:

declare function consoleLog(message: string): void;

export function myExportedFunctionThatWillCallConsoleLog(): void {
  consoleLog("Hello from AS!");
}

JavaScript

import { AsBind } from "as-bind";

const wasm = fetch("./path-to-my-wasm.wasm");

const asyncTask = async () => {
  // Instantiate the wasm file, and pass in our importObject
  const asBindInstance = await AsBind.instantiate(wasm, {
    myWasmFileName: {
      consoleLog: message => {
        console.log(message);
      }
    }
  });

  // Should call consoleLog, and log: "Hello from AS!"
  asBindInstance.exports.myExportedFunctionThatWillCallConsoleLog();
};
asyncTask();

Supported Data Types

All primitive types, ie. Numbers (u8, f32, ...) , Strings, Typed Arrays (Uint8Array, Float32Array, ...) are supported. All of those types can also be used with Array<T>.

Custom classes are currently not support, but planned.

Browser SDK

as-bind works with the Browser SDK. For a fully working example, see the browser-sdk example.

Reference API

AsBind

The default exported ESM class of as-bind, also available as import { AsBind } from "as-bind" / const { AsBind } = require('as-bind').

Class Properties

The AsBind class is meant to vaguely act as the WebAssembly Object exposed to JavaScript environments.

version

AsBind.version: string

Value that is the current version of your imported AsBind.

instantiate
AsBind.instantiate: (
  moduleOrBuffer: (
    WebAssembly.Module |
    BufferSource |
    Response |
    PromiseLike<WebAssembly.Module>
  ),
  imports?: WasmImports
) => Promise<AsBindInstance>`

This function is the equivalent to the AssemblyScript Loader instantiate function, which is similar to the WebAssembly.instantiateStreaming function. It essentially takes as its parameters:

  • Any type of object that can be (resolved) and instantied into a WebAssembly instance. Which in our case would be an AsBindInstance.

  • A WebAssembly importObject, which would have all of your imported functions that can be called from within your AssemblyScript module.

instantiateSync
AsBind.instantiateSync: (
  moduleOrBuffer: (
    WebAssembly.Module |
    BufferSource
  ),
  imports?: WasmImports
) => AsBindInstance`

This is a synchronous version of AsBind.instantiate. This does not accept a promise-like as its module, and returns an AsBindInstance instead of a Promise that resolves an AsBindInstance. This is only reccomended for use in testing or development. Please see the Documentation sections for AsBind.instantiate for more information.

Instance Properties

An AsBindInstance is vaguely similar to a WebAssembly instance.

loadedModule

The raw, untouched instance of the WebAssembly Module.

exports

Similar to to WebAssembly.Instance.prototype.exports, this is an object containing all of the exported fields from the WebAssembly module. However, exported functions are bound / wrapped in which they will handle passing the supported high-level data types to the exported AssemblyScript function.

importObject

Similar to to WebAssembly.instantiateStreaming() importObject, this is the augmented importObject. It’s based on the original that was passed to one of the instantiation functions, but functions have been wrapped to handle high-level types.

Motivation

This library was inspired by several chats I had with some awesome buddies of mine in the WebAssembly Community:

  • Till Schneidereit and I had a chat about WasmBoy, and about how I had a really good experience writing the emulator, even though I had to do my own memory management. But they helped me realize, building something low level isn't that bad with manual memory management, but building something like a markdown parser would be very tedious since you have to manually write the string back and forth. Which then inspired this library, and its markdown parser demo.

  • While I was building WasmByExample I wanted to start building the "High Level Data Structures" section. I then realized how much work it would be to maintain code for passing data between WebAssembly Linear memory would be for each data type, and how much work it would be to created each individual example. Then, my buddy Ashley Williams helped me realize, if your docs are becoming too complex, it may be a good idea to write a tool. That way you have less docs to write, and users will have an easier time using your stuff!

Thus, this library was made to help AssemblyScript/JavaScript users build awesome things! I also want to give a huge thanks to the AssemblyScript team and community for the help they provided me. I'm super appreciative of you all! 😄🎉

(Also! Huge Shoutout to @surma for doing the awesome refactor to use AssemblyScript compiler transforms! 🙏)

Performance

TL;DR This library should be pretty darn fast. 🤔

The transform embeds all the required type information of imported and exported functions into a custom section of the WebAssembly module. All the runtime does is utilize the AssemblyScript Loader to convert these types from JS to ASC and vice-versa. Apart from Array<T>, which needs to be handled recursively, the overhead is fairly static and minimal.

In the future, these types of high-level data passing tools might not be needed at all, as the WebAssembly Inteface Types proposal aims to give WebAssembly an understanding of higher-level types.

Projects using as-bind

  • The as-bind example is a Markdown Parser, in which as-bind takes in a string, passes it to a rough markdown parser / compiler written in AssemblyScript, and returns a string. (Live Demo), (Source Code)

  • use-as-bind is a React hook for using as-bind with an as-bind enabled WASM source. It's goal is to provide a simple API for React users to add WASM to their apps. (Live Demo)

  • as-loader is a webpack loader for AssemblyScript with built-in as-bind support.

If you're project is using as-bind, and you would like to be featured here. Please open a README with links to your project, and if appropriate, explaining how as-bind is being used. 😊

Contributing

Contributions are definitely welcome! Feel free to open a PR for small fixes such as typos and things. Larger fixes, or new features should start out as an issue for discussion, in which then a PR should be made. 🥳

This project will also adhere to the AssemblyScript Code of Conduct.

License

MIT. 📝

More Repositories

1

wasmboy

Game Boy / Game Boy Color Emulator Library, 🎮written for WebAssembly using AssemblyScript. 🚀Demos built with Preact and Svelte. ⚛️
WebAssembly
1,395
star
2

wasm-by-example

Wasm By Example is a website with a set of hands-on introduction examples and tutorials for WebAssembly (Wasm)
JavaScript
491
star
3

vaporBoy

Gameboy / Gameboy Color Emulator PWA built with Preact. ⚛️ Powered by wasmBoy. 🎮Themed with VaporWave. 🌴🐬
JavaScript
254
star
4

live-stream-radio

24/7 live stream video radio station CLI / API 📹 📻
JavaScript
242
star
5

picoDeploy

Deploy Pico-8 Carts as Standalone Applications on Desktop 🖥️(Electron) and Mobile 📱(Ionic) 📦👾
TypeScript
220
star
6

made-with-webassembly

A showcase of awesome production applications, side projects, and use cases made with WebAssembly (Wasm). 👷
JavaScript
210
star
7

aesthetic-css

A vaporwave CSS framework 🌴🐬
CSS
199
star
8

wasm-matrix

A Matrix effect in your terminal using AssemblyScript 🚀 and WASI 🧩 . Deployed to WAPM 📦 .
TypeScript
70
star
9

responsive-gamepad

Handle Keyboard, Gamepad, and Touch Controls under a single API 🕹️
JavaScript
44
star
10

dotFiles

A repo containing all the cool stuff that makes my ~ feel like $HOME. 🏠
Shell
14
star
11

pocketChipScripts

Some nice scripts to ease the process of pocket chip-ing
Shell
12
star
12

wasm-containerization-talk

Examples featured in my "The Legend of WebAssembly, and the Missing Link" talk. Mostly trying to show off how we can use Wasm and Wasi to containerize applications.
C
8
star
13

Stats-Monitor-Widget

A conky like system monitor widget for android
Java
6
star
14

as-date

Staging AssemblyScript Date implementation by @LiaoPeng , as an installable AssemblyScript library
TypeScript
6
star
15

simple-pastebin

A Chrome Extension that is literally just a <textarea>, that saves to localStorage. Paste stuff, and it automatically saves as you paste/type! 📋
JavaScript
6
star
16

sass-bem-mixins

importable Sass BEM mixins
SCSS
4
star
17

assemblyscript-website

JavaScript
4
star
18

radical-rumble-robots

A fighting game for the GameBoy
C
4
star
19

Decisions

A simple decision making app for android
Java
4
star
20

wasi-syscall-playground

A repo for little wasi wat demos I am making for syscalls I am hoping that will exist one day 😂
WebAssembly
3
star
21

wasm-playground

A Wasm playground with preact as a shell, and assemblyscript as the wasm build tool
JavaScript
3
star
22

as-bind-hello-world

A hello world for as-bind.
WebAssembly
3
star
23

crunchkey-2

It's Crunchkey, but 2. Built with AssemblyScript (WebAssembly)!
TypeScript
3
star
24

vagrantBox

Vagrant files to make my life ALOT easier, it will set up virtual dev environments for all of my codes
Shell
3
star
25

shared-gb-js

Shared JS code between my Gameboy Projects 🎮
JavaScript
2
star
26

Crunchkey-Web

A website for the instant calculator chrome plugin, Made this for a class when I first learned some webdev
HTML
2
star
27

link-drops

A collection of your links that you find across the internet, made with the help of @julianpoy
CSS
2
star
28

TxtNote

A simple .txt note taking app for android
Java
2
star
29

chipGo

Another Chip-8 Emulator Written in Go
Go
2
star
30

CrunchKey

Chrome plugin to calculate strings realtime
JavaScript
2
star
31

StarSamurai

Project for BeachHacks 2016, 2d action platformer game. Built in Unity
C#
2
star
32

pixel-pages

Simple landing pages meant to send page view and conversion events to tracking pixels
JavaScript
1
star
33

devops

My devops setup and tools for my servers
HTML
1
star
34

PersonalSite

My old website to showcase my work and portfolio. Made in AngularJS
CSS
1
star
35

link-drops-chrome-extension

The Official Chrome Extension for linkDrops!
JavaScript
1
star
36

as-regex-wasi-demo

A demo of trying assemblyscript-regex in a WASI context
WebAssembly
1
star
37

CECS343JavaResturant

Resturant group project for CECS 343
Java
1
star
38

piStreamRadio-frontend

A frontend web client for piStreamRadio
HTML
1
star
39

pubx

Really simple pub/sub state management 📋
JavaScript
1
star
40

CECS-476-SysAdmin

Homeworks for 476
Python
1
star
41

Feather

A Media/Video Playing app for android
Java
1
star
42

as-echo

A very simple `echo` implementation in AssemblyScript. 🚀
WebAssembly
1
star
43

small-rust-wasm-hello-world

Just a super small rust wasm hello world. Wanted to see how big it would be in bytes :)
Rust
1
star
44

working-group

A repo for discussions, goals, roadmaps, assets, and other things related to the AssemblyScript project.
1
star
45

Transplant-Client

A beautiful Electron SFTP/FTP Client
JavaScript
1
star
46

amp-mutations-benchmark

Tool to benchmark mutation operations on an amp page
JavaScript
1
star
47

personal-site-amp

My personal website, made in AMP
HTML
1
star
48

wasmer-js-playground

Playground for testing wasmer-js
JavaScript
1
star
49

dotRetropie

Config and Dotfiles for retropie
Squirrel
1
star
50

CrunchKey-Ionic

Crunchkey Created in Ionic, for Web and Mobile
CSS
1
star
51

wasmboy-plugin-hqx

Plugin for WasmBoy to add support for hqx upscaling. Built with Rust for WebAssembly.
JavaScript
1
star