Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/oltdaniel/zig-js-interplay

Seamless integration of Zig and JavaScript in WebAssembly
https://github.com/oltdaniel/zig-js-interplay

js wasm zig

Last synced: about 2 months ago
JSON representation

Seamless integration of Zig and JavaScript in WebAssembly

Awesome Lists containing this project

README

        

# Zig JS Interplay

> **DISCLAIMER**: This is a project for fun. There will only be a loose versioning. There are no guarantees.

Dealing with a low level environment like WebAssembly via JavaScript is not easy. Many concepts of low-level languages are being pulled into a very high-level JavaScript environment, reducing the suppleness of the code and interface between both environments.

This library avoids this by pulling high-level concepts into the low-level environment of the WebAssembly source and wrapping it in such fashion, that it can be called and treated like any other JavaScript interface.

The implementation is not necessarly restricted to Zig WebAssembly source, but rather the definition of the interfaces it exposes to the JavaScript environment. The concept can be adapted to any other language that compiles to WebAssembly and offers the necessary capabilities. Zig has been chosen for fun and exploration.

## Example

```zig
const std = @import("std");
const ipl = @import("zig-js-interplay");

export fn greet(name: ipl.String) ipl.String {
// Generate a new greet message that we can return
const greetMessage = std.fmt.allocPrint(ipl.allocator, "Hello {s}!", .{name}) catch @panic("Oops");
// Return with Interplay String
return ipl.String.init(greetMessage);
}

export fn testFunction(arg: ipl.Function) ipl.AnyType {
// Construct function arguments to pass
const args = ipl.Array.from(&.{ ipl.String.init("Hello").asAny(), ipl.String.init("World").asAny() });
// Call the function and return its return value
return arg.call(args);
}
```

```js
import InterplayInstance from 'zig-js-interplay';

const inst = new InterplayInstance.initializeFromUrl('main.wasm');

console.log(inst.greet("Daniel"))
// => prints "Hello Daniel!"

console.log(inst.testFunction((...args) => {
console.log('I got called by reference from Zig with these arguments =', args)
return "JS says hello!"
}))
// => prints "I got called by reference from Zig with these arguments = ['Hello', 'World']"
// => prints "JS says hello!"
```

## Installation

### Requirements

The required browser versions can easily be extracted via [Browserlist](https://browsersl.ist/#q=supports+es6-module+and+supports+wasm+and+supports+wasm-bigint+and+supports+bigint) with the query `supports es6-module and supports wasm and supports wasm-bigint and supports bigint`. The support for `es6-modules` obviously only counts for the compiled JavaScript files this repo contains directly. All the other features must be supported in order to work correctly.

Supported browser versions (as of 2024-07-15):
- Chrome 85+
- Safari iOS 14.5+
- Safari 14.1+
- Firefox 78+

### Zig

![GitHub file size in bytes](https://img.shields.io/github/size/oltdaniel/zig-js-interplay/example%2Fmain.wasm)

First, add this repo as an dependency to your Zon file with `zig fetch https://github.com/oltdaniel/zig-js-interplay/archive/COMMITSHA.tar.gz --save`.

And add the following code to add this repo as a module you can import to your `build.zig`:

```zig
// ...

// Load depdendency
const zigJsInterplay = b.dependency("zig-js-interplay", .{});

// Add dependency to root module
wasm.root_module.addImport("zig-js-interplay", zigJsInterplay.module("zig-js-interplay"));

// ...
```

> **NOTE**: I'm still new to zig, so if there is a better way, please let me know.

The binary size of a full example using all types, including the builtin wasm allocator, a hash function and string formatting, can be seen above.

### JavaScript

![GitHub file size in bytes](https://img.shields.io/github/size/oltdaniel/zig-js-interplay/dist%2Finterplay.min.js)

You can simply import the module within your source. The current bundle size can be seen above.

```html

import InterplayInstance from 'https://cdn.jsdelivr.net/gh/oltdaniel/zig-js-interplay/dist/interplay.min.js';

```

Right now we don't publish this package to an registry. But you can simply add this repo as a dependency via the package manager of your choice. We only rely on a single development dependency. Alternatively you can use a CDN like [jsdelivr](https://www.jsdelivr.com/) or [unpkg](https://unpkg.com/).

## Documentation

> **TODO**: Write documentation.

Currently, there are a lot of technical comments in the source code itself and in the example. Please read those for now instead.

### Articles

I've written two articles about my process to this library. Feel free to check them out:

- [Playing with zig and wasm](https://oltdaniel.eu/blog/2024/playing-with-zig-and-wasm.html)
- [TODO](#)

## Development

This project consists of two programming languages. We require a JavaScript and Zig toolchain for full development on this project.

- [Node.js](https://nodejs.org) for the JavaScript toolchain environment.
- [PNPM](https://pnpm.io/) as JavaScript package manage of choice for this project.
- [Zig](https://ziglang.org/) for the Zig toolchain (`v0.13` has been used during development by me).

```bash
# Get the source code
git clone https://github.com/oltdaniel/zig-js-interplay
cd zig-js-interplay

# Compile JavaScript and Zig
# NOTE: This runs `pnpm build` and `zig build`
make

# Compile JavaScript
pnpm build

# Compile Zig
# NOTE: There is no compile output for Interplay alone. But it checks if everything is ok.
zig build

# Compile example
cd example
zig build

# Serve example via HTTP server
# http://localhost:8000/example
python -m http.server 8000
```

### ToDo

- [ ] Comment the zig file correctly and in full form
- [ ] Maybe add some tests for the functionns on each side
- [ ] Write documentation for the encoding and how each type works

## License

![MIT License](https://img.shields.io/github/license/oltdaniel/zig-js-interplay)