Skip to content

Commit

Permalink
Merge pull request wasmerio#357 from wasmerio/michael/sdk-34-updated-…
Browse files Browse the repository at this point in the history
…wasmersdk-readme

Update the README
  • Loading branch information
Michael Bryan authored Dec 13, 2023
2 parents d14f342 + c954f56 commit 54ed7dd
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 138 deletions.
64 changes: 64 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## Contributing Guide

### Building

To build this library you will need to have installed in your system:

* Node.JS
* [Rust][Rust]
* [wasm-pack][wasm-pack]
* [wabt][wabt] (for `wasm-strip`)
* [binaryen][binaryen] (for `wasm-opt`)

```sh
npm install
npm run build
```

There is also a command for compiling the Rust in debug mode. This tends to be
a lot faster and includes thread-safety checks.

```sh
npm run build:dev
```

### Testing

Build the package and run the tests:

```sh
npm run build:dev
npm run test
```

### Releasing

This repository uses [Release Please][release-please] to automate a lot of the
work around creating releases.

Every time a commit following the [Conventional Commit Style][conv] is merged
into `main`, the [`release-please.yml`](.github/workflows/release-please.yml)
workflow will run and update the "Release PR" to reflect the new changes.

For commits that just fix bugs (i.e. the message starts with `"fix: "`), the
associated crate will receive a changelog entry and a patch version bump.
Similarly, adding a new feature (i.e. `"feat:"`) does a minor version bump and
adding breaking changes (i.e. `"fix!:"` or `"feat!:"`) will result in a major
version bump.

When the release PR is merged, the updated changelog and bumped version number
will be merged into the `main` branch, the `release-please.yml` workflow will
automatically generate GitHub Releases, and CI will publish the package to NPM.

TL;DR:

1. Use [Conventional Commit Messages][conv] whenever you make a noteworthy change
2. Merge the release PR when ready to release
3. Let the automation do everything else

[binaryen]: https://github.com/WebAssembly/binaryen
[conv]: https://www.conventionalcommits.org/en/v1.0.0/
[release-please]: https://github.com/googleapis/release-please
[Rust]: https://www.rust-lang.org/
[wabt]: https://github.com/WebAssembly/wabt
[wasm-pack]: https://rustwasm.github.io/wasm-pack/
226 changes: 89 additions & 137 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,182 +1,134 @@
# <img height="48" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/logo.png" alt="Wasmer logo" valign="middle"> Wasmer JS [![Wasmer Slack Channel](https://img.shields.io/static/v1?label=chat&message=on%20Slack&color=green)](https://slack.wasmer.io)
# The Wasmer JavaScript SDK

This repository consists of multiple packages:
* [Wasmer WASI](#wasmer-wasi)
[![npm (scoped)](https://img.shields.io/npm/v/%40wasmer/sdk)](https://npmjs.org/package/@wasmer/sdk)
[![NPM Downloads](https://img.shields.io/npm/dm/%40wasmer%2Fsdk)](https://npmjs.org/package/@wasmer/sdk)
[![License](https://img.shields.io/npm/l/%40wasmer%2Fsdk)](./LICENSE)
[![Wasmer Discord Channel](https://img.shields.io/discord/1110300506942881873)](https://discord.gg/qBTfsNP7N8)
[![API Docs](https://img.shields.io/badge/API%20Docs-open-blue?link=wasmerio.github.io%2Fwasmer-js%2F)](https://wasmerio.github.io/wasmer-js/)

# Wasmer WASI
Isomorphic Javascript library for running WASI programs.

Isomorphic Javascript library for interacting with WASI Modules in Node.js, the Browser and [Deno](https://deno.land/x/wasm).
The Javascript Package supports:
* [X] WASI (with command args, envs and stdio)
* [X] In-Memory filesystem (MemFS)

### NPM
* [X] WASI support
* [X] Environment variables
* [X] FileSystem access
* [X] Command-line arguments
* [X] Stdio
* [X] WASIX support
* [X] Multi-threading
* [X] Spawning sub-processes
* [ ] Networking
* [X] Mounting directories inside the WASIX instance
* [X] Running packages from the [Wasmer Registry](https://wasmer.io)
* Platforms
* [X] Browser
* [ ] NodeJS
* [ ] Deno

For instaling `@wasmer/wasi` run this command in your shell:
## Getting Started

### Install from NPM

For instaling `@wasmer/sdk`, run this command in your shell:

```bash
npm install --save @wasmer/wasi
npm install --save @wasmer/sdk
```

And then import it in your server or client-side code with:
You can now run WASI packages from the Wasmer registry:

```js
import { init, WASI } from '@wasmer/wasi';
```

> Check the Node usage examples in https://github.com/wasmerio/wasmer-js/tree/main/examples/node
import { init, Wasmer } from "@wasmer/sdk";

### Deno
await init();

This package is published in Deno in the `wasm` package, you can import it directly with:
const pkg = await Wasmer.fromRegistry("python/[email protected]");
const instance = await pkg.entrypoint.run({
args: ["-c", "print('Hello, World!')"],
});

```ts
import { init, WASI } from 'https://deno.land/x/wasm/wasi.ts';
const { code, stdoutUtf8 } = await instance.wait();
console.log(`Python exited with ${code}: ${stdoutUtf8}`);
```

> Check the Deno usage Examples in https://github.com/wasmerio/wasmer-js/tree/main/examples/deno
### Install from CDN

## Usage
It is possible to avoid needing to use a bundler by importing `@wasmer/sdk` as
a UMD module.

```js
// This is needed to load the WASI library first (since is a Wasm module)
await init();
By adding the following `<script>` tag to your `index.html` file, the library
will be available as the `WasmerSDK` global variable.

let wasi = new WASI({
env: {
// 'ENVVAR1': '1',
// 'ENVVAR2': '2'
},
args: [
// 'command', 'arg1', 'arg2'
],
});

const moduleBytes = fetch("https://deno.land/x/wasm/tests/demo.wasm");
const module = await WebAssembly.compileStreaming(moduleBytes);
// Instantiate the WASI module
await wasi.instantiate(module, {});
```html
<script src="https://unpkg.com/@wasmer/sdk@latest"></script>
<script>
const { init, Wasmer } = WasmerSDK;
// Run the start function
let exitCode = wasi.start();
let stdout = wasi.getStdoutString();
async function runPython() {
await init();
// This should print "hello world (exit code: 0)"
console.log(`${stdout}(exit code: ${exitCode})`);
```
const packageName = "python/[email protected]";
const pkg = await Wasmer.fromRegistry(packageName);
const instance = await pkg.entrypoint.run({
args: ["-c", "print('Hello, World!')"],
});
## API Docs

<!-- Please check the full API documents here:
https://docs.wasmer.io/integrations/js/reference-api -->

### Typescript API

```typescript
export class WASI {
constructor(config: any);
readonly fs: MemFS;

instantiate(module: any, imports: object): WebAssembly.Instance;
// Start the WASI Instance, it returns the status code when calling the start
// function
start(instance: WebAssembly.Instance): number;
// Get the stdout buffer
// Note: this method flushes the stdout
getStdoutBuffer(): Uint8Array;
// Get the stdout data as a string
// Note: this method flushes the stdout
getStdoutString(): string;
// Get the stderr buffer
// Note: this method flushes the stderr
getStderrBuffer(): Uint8Array;
// Get the stderr data as a string
// Note: this method flushes the stderr
getStderrString(): string;
// Set the stdin buffer
setStdinBuffer(buf: Uint8Array): void;
// Set the stdin data as a string
setStdinString(input: string): void;
}

export class MemFS {
constructor();
readDir(path: string): Array<any>;
createDir(path: string): void;
removeDir(path: string): void;
removeFile(path: string): void;
rename(path: string, to: string): void;
metadata(path: string): object;
open(path: string, options: any): JSVirtualFile;
}

export class JSVirtualFile {
lastAccessed(): BigInt;
lastModified(): BigInt;
createdTime(): BigInt;
size(): BigInt;
setLength(new_size: BigInt): void;
read(): Uint8Array;
readString(): string;
write(buf: Uint8Array): number;
writeString(buf: string): number;
flush(): void;
seek(position: number): number;
}
```
const { code, stdoutUtf8 } = await instance.wait();
## Building
console.log(`Python exited with ${code}: ${stdoutUtf8}`);
}
To build this library you will need to have installed in your system:
runPython();
</script>
```

* Node.JS
* [Rust][Rust]
* [wasm-pack][wasm-pack]
* [wabt][wabt] (for `wasm-strip`)
* [binaryen][binaryen] (for `wasm-opt`)
Alternatively, the package can be imported directly from the CDN by turning the
script into a module.

```sh
npm i
npm run build
```
```html
<script defer type="module">
import { init, Wasmer } from "https://unpkg.com/@wasmer/sdk@latest/dist/Library.mjs";
## Testing
async function runPython() {
await init();
Build the pkg and run the tests:
...
}
```sh
npm run build
npm run test
runPython();
</script>
```

# What is WebAssembly?
### Cross-Origin Isolation

Quoting [the WebAssembly site](https://webassembly.org/):
Browsers have implemented security measures to mitigate the Spectre and Meltdown
vulnerabilities.

> WebAssembly (abbreviated Wasm) is a binary instruction format for a
> stack-based virtual machine. Wasm is designed as a portable target
> for compilation of high-level languages like C/C++/Rust, enabling
> deployment on the web for client and server applications.
These measures restrict the sharing of `SharedArrayBuffer`` objects with Web
Workers unless the execution context is deemed secure.

About speed:
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.

> WebAssembly aims to execute at native speed by taking advantage of
> [common hardware
> capabilities](https://webassembly.org/docs/portability/#assumptions-for-efficient-execution)
> available on a wide range of platforms.
To avoid Cross-Origin Isolation issues, make sure any web pages using
`@wasmer/sdk` are served over HTTPS and have the following headers set:

About safety:
```yaml
"Cross-Origin-Opener-Policy": "same-origin"
"Cross-Origin-Embedder-Policy": "require-corp"
```
> WebAssembly describes a memory-safe, sandboxed [execution
> environment](https://webassembly.org/docs/semantics/#linear-memory) [].
See the [`SharedArrayBuffer` and Cross-Origin Isolation][coi-docs] section under
the *Troubleshooting Common Problems* docs for more.

# License

The entire project is under the MIT License. Please read [the
`LICENSE` file][license].

[coi-docs]: https://docs.wasmer.io/javascript-sdk/explainers/troubleshooting#sharedarraybuffer-and-cross-origin-isolation
[license]: https://github.com/wasmerio/wasmer/blob/master/LICENSE
[Rust]: https://www.rust-lang.org/
[wasm-pack]: https://rustwasm.github.io/wasm-pack/
[wabt]: https://github.com/WebAssembly/wabt
[binaryen]: https://github.com/WebAssembly/binaryen
43 changes: 43 additions & 0 deletions examples/cdn/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wasmer JavaScript SDK</title>
<script defer type="module">
import { init, Wasmer } from "https://unpkg.com/@wasmer/sdk@latest/dist/Library.mjs";

async function runPython() {
const status = document.getElementById("status");

status.innerHTML = "Initializing...";
await init();

const packageName = "python/[email protected]";
status.innerHTML = `Fetching ${packageName}...`;
const pkg = await Wasmer.fromRegistry(packageName);

status.innerHTML = `Starting ${packageName}...`;
const instance = await pkg.entrypoint.run({
args: ["-c", "print('Hello, World!')"],
});

status.innerHTML = `Running ${packageName}...`;
const { code, stdoutUtf8 } = await instance.wait();

status.innerHTML = `Exited with status code: ${code}`;
const stdout = document.getElementById("stdout");
stdout.innerHTML = stdoutUtf8;
}

runPython();
</script>
</head>

<body>
<h1 id="status"></h1>
<pre><code id="stdout"></code></pre>
</body>

</html>
2 changes: 1 addition & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const makeConfig = (env = "development") => {
output: [
{
banner,
name: LIBRARY_NAME,
name: "WasmerSDK",
file: `dist/${LIBRARY_NAME}.umd.js`,
format: "umd",
exports: "auto",
Expand Down

0 comments on commit 54ed7dd

Please sign in to comment.