Skip to content

Commit

Permalink
feat(examples): add HTTP hello world (#533)
Browse files Browse the repository at this point in the history
* chore(examples): update jco/componentize-js versions

Signed-off-by: Victor Adossi <[email protected]>

* feat(examples): add HTTP hello world example

This commit adds an example that uses the WASI http world to build a
HTTP handler to the in-repo examples.

Signed-off-by: Victor Adossi <[email protected]>

* chore(examples): update http example wasi deps to 0.2.2

Signed-off-by: Victor Adossi <[email protected]>

* fix(examples): remove type generation

Signed-off-by: Victor Adossi <[email protected]>

* docs(examples): add warning about jco serve for local/dev use

Signed-off-by: Victor Adossi <[email protected]>

---------

Signed-off-by: Victor Adossi <[email protected]>
  • Loading branch information
vados-cosmonic authored Dec 11, 2024
1 parent 381df49 commit c8c04b4
Show file tree
Hide file tree
Showing 27 changed files with 6,118 additions and 148 deletions.
107 changes: 61 additions & 46 deletions examples/components/add/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions examples/components/add/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"all": "npm run build && npm run transpile && npm run transpiled-js"
},
"devDependencies": {
"@bytecodealliance/jco": "1.7.1",
"@bytecodealliance/componentize-js": "0.13.1"
"@bytecodealliance/jco": "1.8.1",
"@bytecodealliance/componentize-js": "0.15.0"
}
}
4 changes: 4 additions & 0 deletions examples/components/http-hello-world/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
*.wasm
pnpm-lock.yaml
1 change: 1 addition & 0 deletions examples/components/http-hello-world/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v22.5.1
153 changes: 153 additions & 0 deletions examples/components/http-hello-world/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# WASI `http-hello-world` in JavaScript

This folder contains a WebAssembly Javascript component that uses [`wasi:http`][wasi-http] for enabling HTTP handlers in Javascript.

It uses [`jco`][jco] to:

- Generate a WebAssembly component (via `jco componentize`) that can be executed by a WebAssembly runtime (ex. [`wasmtime serve`][wasmtime])

[nodejs]: https://nodejs.org
[jco]: https://bytecodealliance.github.io/jco/
[wasi-http]: https://github.com/WebAssembly/wasi-http
[wasmtime]: https://github.com/bytecodealliance/wasmtime

# Quickstart

## Dependencies

First, install required dependencies:

```console
npm install
```

> [!NOTE]
> As this is a regular NodeJS project, you can use your package manager of choice (e.g. `yarn`, `pnpm`)
At this point, since this project is *just* NodeJS, you could use the module from any NodeJS project or browser project where appropriate.

That said, we'll be focusing on building the JS code we've written so far into a WebAssembly binary, which can run *anywhere* WebAssembly runtimes are supported,
including in other languages, and the browser.

## Building the WebAssembly component

We can build a WebAssembly component binary out of this JS project with `jco`:

```console
npm run build
```

A WebAssembly binary will be written to `string-reverse.wasm`.

## Serving web requests with the WebAssembly component

To run the component and serve requests we can either use `jco` or `wasmtime`:

```console
$ jco serve http-hello-world.wasm
Server listening on 8000...
```

> [!WARN]
> `jco serve` is meant to be used for local/development environments, not production use cases.
Similarly you can also use `wasmtime`:

```
$ wasmtime serve -S common http-hello-world.wasm
Serving HTTP on http://0.0.0.0:8080/
```

With either approach, you can use `curl` the appropriate URL to trigger your WebAssembly component.

> [!NOTE]
> The implementations of `jco serve` and `wasmtime serve` are what actually *fulfill* all the imports
> of your component (see combined/merged `world root` above), and use the `wasi:http/incoming-handler` *export*
> to make web serving actually happen.
# How it works

## Exploring this Component WIT

As WebAssembly components are powered by a [WebAssembly Interface Types ("WIT")][wit]-first workflow, making
a HTTP handler component in WebAssembly requires creating a WIT contract to represent that component.

This folder contains a `wit` directory (by convention) with the following content in `component.wit`:

```wit
package example:http-hello-world;
world component {
export wasi:http/[email protected];
}
```

> [!NOTE]
> See [`wit/component.wit`](./wit/component.wit)
>
> For more information on the WIT syntax, see [WIT design docs][wit]
We make use of the [WebAssembly System Interface ("WASI") HTTP][wasi-http] interface here, pulling in
pre-established interfaces interfaces for serving *incoming* HTTP requests.

[wasi-http]: https://github.com/WebAssembly/wasi-http
[wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md

## Resolving references WebAssembly types

As we intend to use the WASI HTTP interface, we need to pull in WIT interface(s) and types that are referred to by
the `wasi:http/incoming-handler` interface.

One way fo doing this is *downloading* the WIT from Bytecode Alliance repositories, using [`wkg`, from the `bytecodealliance/wasm-pkg-tools`][wkg].

Since WASI is a growing standard, and well integrated we can generally follow the error messages:

```console
wkg get wasi:[email protected]
wkg get wasi:[email protected]
wkg get wasi:[email protected]
wkg get wasi:[email protected]
wkg get wasi:[email protected]
wkg get wasi:[email protected]
wkg get wasi:[email protected]
```

> [!NOTE]
> How do we know all these are required? After getting `wasi:http` you can generally follow the error messages.
This will add many WIT files to your local repository, but you can move/rename all the downloaded `*.wit` files
by making a folder named `deps` under `wit` and dropping them there.

```console
mkdir wit/deps
mv *.wit wit/deps
```

## Building our component

To turn our JS into a WebAssembly component, we can use `jco componentize`:

```console
jco componentize http-hello-world.js --wit wit/ --world-name component --out http-hello-world.wasm
```

> [!NOTE]
> For ease, you can do all of this with `pnpm build` or `npm run build`, or your npm-compatible build tool of choice.
You should see output like the following:

```
pnpm build
> http-hello-world-wasm@ build /path/to/jco/examples/components/http-hello-world
> jco componentize http-hello-world.js --wit wit/ --world-name component --out http-hello-world.wasm
OK Successfully written http-hello-world.wasm.
```

Now that your component has been built, we can do *alot* of things to inspect it. Here are a few:

```
➜ file http-hello-world.wasm
http-hello-world.wasm: WebAssembly (wasm) binary module version 0x1000d
```
Loading

0 comments on commit c8c04b4

Please sign in to comment.