Skip to content

Commit

Permalink
feat(examples): add documentation and walkthroughs for examples (#514)
Browse files Browse the repository at this point in the history
* feat(examples): add documentation and walkthroughs for examples

This commit adds documentation along with walkthroughs for how to use
`jco` when building and deploying WebAssembly components.

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

* refactor(ci): use the all target for examples

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

* chore(ci): run examples on every push to main

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

---------

Signed-off-by: Victor Adossi <[email protected]>
Co-authored-by: Guy Bedford <[email protected]>
  • Loading branch information
vados-cosmonic and guybedford authored Nov 1, 2024
1 parent 4f07888 commit d70b4d4
Show file tree
Hide file tree
Showing 23 changed files with 642 additions and 43 deletions.
24 changes: 5 additions & 19 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: examples

on:
push:
branches:
- main
pull_request:
branches:
- main
Expand Down Expand Up @@ -49,24 +52,7 @@ jobs:
run: |
npm install
- name: build (${{ matrix.project.name }})
working-directory: ${{ matrix.project.dir }}
run: |
npm run build
- name: compose (${{ matrix.project.name }})
if: ${{ matrix.project.is-composed }}
working-directory: ${{ matrix.project.dir }}
run: |
npm run compose
- name: transpile (${{ matrix.project.name }})
working-directory: ${{ matrix.project.dir }}
run: |
npm run transpile
- name: run transpiled js (${{ matrix.project.name }})
if: ${{ matrix.project.composed }}
- name: run all script for (${{ matrix.project.name }})
working-directory: ${{ matrix.project.dir }}
run: |
npm run transpiled-js
npm run all
16 changes: 16 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Examples

This folder contains examples of using `jco`, `componentize-js`, and related Javascript WebAssembly runtime tooling.

The following sections are present:

- [Example Components](./components) - "Just show me the code" examples of how to build JS projects that use `jco`
- [Guides](./guides) - Walkthroughs of concepts and functionality to keep in mind while using `jco` and associated tooling

> [!NOTE]
> Note sure what WebAssembly "Components" are, relative to WebAssembly modules?
>
> For an in-depth multi-language guide to the concepts and advanced features behind the Component Model,
> [read the Component Model book][cm-book].
[cm-book]: https://component-model.bytecodealliance.org/
14 changes: 14 additions & 0 deletions examples/components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Example Components

Most (if not all) individual example projects are standard Javascript projects commonplace ecosystem tooling, whether
for server side ([NodeJS][nodejs] -- `npm`, etc) or the browser.

A brief description of the examples contained in this folder:

| Example | Description |
|--------------------------------------------------|--------------------------------------------------------------------------------------------------|
| [`add`](./add) | `export`s basic functionality with simple types |
| [`string-reverse`](./string-reverse) | `export`s basic functionality with a slightly more involved WIT interface and more complex types |
| [`string-reverse-upper`](./string-reverse-upper) | `import`s functionality to build more advanced computation to `export` |

[nodejs]: https://nodejs.org
3 changes: 2 additions & 1 deletion examples/components/add/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist
*.wasm
*.wasm
pnpm-lock.yaml
File renamed without changes.
12 changes: 6 additions & 6 deletions examples/components/add/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"description": "Simple codebase for compiling an add function to WebAssembly with jco",
"type": "module",
"scripts": {
"build": "jco componentize add.mjs --wit wit/component.wit --world-name component --out add.wasm --disable all",
"transpile": "jco transpile add.wasm -o dist/transpiled ; cp dist/transpiled/add.js dist/transpiled/add.mjs",
"start": "cargo run --manifest-path=../../../example-host/Cargo.toml --release -- 1 2 add.wasm",
"transpiled-js": "node run-transpiled.js"
"build": "jco componentize add.js --wit wit/component.wit --world-name component --out add.wasm --disable all",
"transpile": "jco transpile add.wasm -o dist/transpiled",
"transpiled-js": "node run-transpiled.js",
"all": "npm run build && npm run transpile && npm run transpiled-js"
},
"devDependencies": {
"@bytecodealliance/jco": "1.7.0",
"@bytecodealliance/componentize-js": "0.13.0"
"@bytecodealliance/jco": "1.7.1",
"@bytecodealliance/componentize-js": "0.13.1"
}
}
2 changes: 1 addition & 1 deletion examples/components/add/run-transpiled.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// If this import listed below is missing, please run `npm run transpile`
import { add } from "./dist/transpiled/add.mjs";
import { add } from "./dist/transpiled/add.js";

console.log("1 + 2 = " + add(1, 2));
3 changes: 2 additions & 1 deletion examples/components/string-reverse-upper/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist
*.wasm
*.wasm
pnpm-lock.yaml
2 changes: 1 addition & 1 deletion examples/components/string-reverse-upper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ dist
├── string-reverse-upper.core2.wasm
├── string-reverse-upper.core.wasm
├── string-reverse-upper.d.ts
└── string-reverse-upper.mjs
└── string-reverse-upper.js
```

With this transpiled code available, we can now run native NodeJS code that will *use* the WebAssembly module:
Expand Down
11 changes: 6 additions & 5 deletions examples/components/string-reverse-upper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
"description": "Simple codebase for reversing a string and upper-casing it via WebAssembly with jco",
"type": "module",
"scripts": {
"build": "jco componentize string-reverse-upper.mjs --wit wit/ --world-name revup --out string-reverse-upper.incomplete.wasm --disable all",
"build": "jco componentize string-reverse-upper.js --wit wit/ --world-name revup --out string-reverse-upper.incomplete.wasm --disable all",
"build:dep": "cd ../string-reverse ; npm run build",
"compose": "npm run build:dep && wac plug --plug ../string-reverse/string-reverse.wasm string-reverse-upper.incomplete.wasm -o string-reverse-upper.wasm",
"transpile": "jco transpile string-reverse-upper.wasm -o dist/transpiled ; mv dist/transpiled/string-reverse-upper.js dist/transpiled/string-reverse-upper.mjs",
"transpiled-js": "node run-transpiled.js"
"transpile": "jco transpile string-reverse-upper.wasm -o dist/transpiled",
"transpiled-js": "node run-transpiled.js",
"all": "npm run build:dep ; npm run build ; npm run compose ; npm run transpile ; npm run transpiled-js"
},
"devDependencies": {
"@bytecodealliance/jco": "1.7.0",
"@bytecodealliance/componentize-js": "0.13.0"
"@bytecodealliance/jco": "1.7.1",
"@bytecodealliance/componentize-js": "0.13.1"
}
}
2 changes: 1 addition & 1 deletion examples/components/string-reverse-upper/run-transpiled.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* npm run build && npm run compose && npm run transpile`
* ```
*/
import { reversedUpper } from "./dist/transpiled/string-reverse-upper.mjs";
import { reversedUpper } from "./dist/transpiled/string-reverse-upper.js";

const result = reversedUpper.reverseAndUppercase("!dlroW olleH");

Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const reversedUpper = {
*
* This function makes use of `reverse-string` which is *imported* from another WebAssembly binary.
*/
reverseAndUppercase() {
reverseAndUppercase(s) {
return reverseString(s).toLocaleUpperCase();
},
};
3 changes: 2 additions & 1 deletion examples/components/string-reverse/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist
*.wasm
*.wasm
pnpm-lock.yaml
11 changes: 6 additions & 5 deletions examples/components/string-reverse/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
"description": "Simple codebase for reversing a string via WebAssembly with jco",
"type": "module",
"scripts": {
"build": "jco componentize string-reverse.mjs --wit wit/component.wit --world-name component --out string-reverse.wasm --disable all",
"transpile": "jco transpile string-reverse.wasm -o dist/transpiled ; mv dist/transpiled/string-reverse.js dist/transpiled/string-reverse.mjs",
"transpiled-js": "node run-transpiled.js"
"build": "jco componentize string-reverse.js --wit wit/component.wit --world-name component --out string-reverse.wasm --disable all",
"transpile": "jco transpile string-reverse.wasm -o dist/transpiled",
"transpiled-js": "node run-transpiled.js",
"all": "npm run build; npm run transpile; npm run transpiled-js"
},
"devDependencies": {
"@bytecodealliance/jco": "1.7.0",
"@bytecodealliance/componentize-js": "0.13.0"
"@bytecodealliance/jco": "1.7.1",
"@bytecodealliance/componentize-js": "0.13.1"
}
}
2 changes: 1 addition & 1 deletion examples/components/string-reverse/run-transpiled.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// If this import listed below is missing, please run `npm run transpile`
import { reverse } from "./dist/transpiled/string-reverse.mjs";
import { reverse } from "./dist/transpiled/string-reverse.js";

const reversed = reverse.reverseString("!dlroW olleH");

Expand Down
34 changes: 34 additions & 0 deletions examples/guides/00-tooling-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 00 - Tooling Setup

To follow along with the guides, you'll need to have the Javscript for WebAssembly toolchain installed,
which means installing [`jco`][jco] and related tooling.

[`jco`][jco] is a fully native JS tool for working with the emerging WebAssembly
Components specification in JavaScript.

> [!NOTE]
> [Typescript][ts] can *also* be used, given that it is transpiled to JS first by relevant tooling (`tsc`).
> `jco` includes a `jco types` subcommand for generating typings that can be used with a Typescript codebase.
[jco]: https://github.com/bytecodealliance/jco
[ts]: https://typescriptlang.org

### Installing `jco`

[`jco`][jco] and [`componentize-js`][componentize-js] can be installed with standard NodeJS tooling:

```console
npm install -g @bytecodealliance/componentize-js @bytecodealliance/jco
```

> [!NOTE]
> `jco` and `componentize-js` can be installed in a project-local manner with `npm install -D`
[ComponentizeJS][componentize-js] provides tooling used by `jco` to transpile JS to Wasm, so installing both packages is required.

[componentize-js]: https://github.com/bytecodealliance/ComponentizeJS

### Contribute to this Guide!

The goal for this guide is to leave zero lingering questions. If you had substantial doubts/unaddressed questions
while going through this guide, [open up an issue](https://github.com/bytecodealliance/jco/issues/new) and we'll improve the docs together.
104 changes: 104 additions & 0 deletions examples/guides/01-building-a-component-with-jco.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# 01 - Building a WebAssembly Component with `jco`

> [!NOTE]
> This guide assumes you have dependencies like `jco` installed already.
>
> Consider referring to the "Tooling setup" guide if your environment hasn't been set up yet.
The first step in building a WebAssembly component is creating or downloading the interface that
defines what your component can do. This usually means creating or downloading the
[WebAssembly Interface Types ("WIT")][wit] world you would like to "target" with your component.

## Writing the WIT

The [example `add` component][examples-add] showcases a component that adds two numbers together.

The WIT interface looks like the following:

```wit
package example:adder;
world component {
export add: func(x: s32, y: s32) -> s32;
}
```

> [!NOTE]
> `export`ing the `add` interface meants that runners of the WebAssembly binary will be able to *call* that function.
>
> To learn more about the WIT syntax, check out the full [WIT specification][wit]
## Writing the Javascript

Along with this WIT interface, we can write a JavaScript module that implements the exported `add` function in the `adder` world:

```js
export function add(x, y) {
return x + y;
}
```
> [!WARN]
> jco only deals with ES modules, so ensure to set `"type": "module"` in your `package.json` if necessary
> [!NOTE]
> In the code above, the JS module *itself* is the `component` world, and `add` function export is satisfied with the `add` JS function.
## Building a WebAssembly Component

With the WIT and Javascript in place, we can use [`jco`][jco] to create a WebAssembly component from the JS module, using `jco componentize`.

Our component is *so simple* (reminiscent of [Core WebAssembly][wasm-core], which deals primarily in numeric values)
that we're actually *not using* any of the [WebAssembly System Interface][wasi] -- this means that we can `--disable` it when we invoke `jco componentize`.

From the [`examples/components/add`][examples-add] folder, you can run `jco componentize`:

```console
jco componentize \
add.js \
--wit path/to/add/world.wit \
--world-name component \
--out add.wasm \
--disable all
```

> [!NOTE]
> You can exclude the `--disable` option and the component will build just fine!
You should see output like the following:

```
OK Successfully written add.wasm.
```

> [!NOTE]
> As the `add` example is a regular [NodeJS][nodejs] project, you can run `npm install && npm run build`
> without having `jco` and `componentize-js` installed globally.
[wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md
[nodejs]: https://nodejs.org/en
[wasi]: https://wasi.dev/
[wasm-core]: https://webassembly.github.io/spec/core/
[jco]: https://github.com/bytecodealliance/jco
[examples-add]: https://github.com/bytecodealliance/jco/tree/main/examples/components/add

## FAQ

### Is this a Reactor component?

"Reactor" components are WebAssembly components that can be called repeatedly over time. This serves uses cases like building HTTP handlers,
but also for serving as libraries in other components.

Reactor components (and components in general) expose their interfaces via [WebAssembly Interface Types][docs-wit],
hand-in-hand with the [Component Model][docs-component-model] which enables components to use higher level types interchangably.

They're analogous to libraries of functionality rather than an executable (a "command" component). By contrast, command components must export
a `_start` function, and *usually* export the [`wasi:cli/run` interface][github-wasi-cli], so that other

[docs-wit]: ../design/wit.md
[docs-component-model]: ../design/why-component-model.md
[github-wasi-cli]: https://github.com/WebAssembly/wasi-cli

### Contribute to this Guide!

The goal for this guide is to leave zero lingering questions. If you had substantial doubts/unaddressed questions
while going through this guide, [open up an issue](https://github.com/bytecodealliance/jco/issues/new) and we'll improve the docs together.
Loading

0 comments on commit d70b4d4

Please sign in to comment.