Skip to content

Commit

Permalink
Merge pull request #106 from kate-goldenring/update-language-guides
Browse files Browse the repository at this point in the history
fix: bring documentation and tutorials up to date with latest tooling
  • Loading branch information
kate-goldenring committed Mar 18, 2024
2 parents c284e70 + a4fbcbd commit 91ba47f
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 238 deletions.
417 changes: 245 additions & 172 deletions component-model/examples/example-host/Cargo.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions component-model/examples/example-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition = "2021"
[dependencies]
async-std = { version = "1.12.0", features = ["attributes"] }
clap = { version = "4.3.19", features = ["derive"] }
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "2ade3ad", features = ["component-model"] }
wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime", rev = "2ade3ad" }
wasi-cap-std-sync = { git = "https://github.com/bytecodealliance/wasmtime", rev = "2ade3ad" }
wasmtime = "18.0.1"
wasmtime-wasi = { version = "18.0.1" }
anyhow = "1.0.72"
20 changes: 6 additions & 14 deletions component-model/examples/example-host/src/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::Context;
use std::path::PathBuf;
use wasmtime::component::*;
use wasmtime::{Config, Engine, Store};
use wasmtime_wasi::preview2::{command, Table, WasiCtx, WasiCtxBuilder, WasiView};
use wasmtime_wasi::preview2::{command, WasiCtx, WasiCtxBuilder, WasiView};

wasmtime::component::bindgen!({
path: "add.wit",
Expand Down Expand Up @@ -34,33 +34,25 @@ pub async fn add(path: PathBuf, x: i32, y: i32) -> wasmtime::Result<i32> {
}

struct ServerWasiView {
table: Table,
table: ResourceTable,
ctx: WasiCtx,
}

impl ServerWasiView {
fn new() -> Self {
let table = Table::new();
let table = ResourceTable::new();
let ctx = WasiCtxBuilder::new().inherit_stdio().build();

Self { table, ctx }
}
}

impl WasiView for ServerWasiView {
fn table(&self) -> &Table {
&self.table
}

fn table_mut(&mut self) -> &mut Table {
fn table(&mut self) -> &mut ResourceTable {
&mut self.table
}

fn ctx(&self) -> &WasiCtx {
&self.ctx
}

fn ctx_mut(&mut self) -> &mut WasiCtx {
fn ctx(&mut self) -> &mut WasiCtx {
&mut self.ctx
}
}
}
2 changes: 1 addition & 1 deletion component-model/examples/tutorial/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ wasm-tools compose command/target/wasm32-wasi/release/command.wasm -d composed.w
Now, run the component with wasmtime:

```sh
wasmtime run --wasm component-model command.wasm 1 2 add
wasmtime run command.wasm 1 2 add
1 + 2 = 3
```
2 changes: 1 addition & 1 deletion component-model/src/creating-and-consuming/composing.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The [`wasm-tools` suite](https://github.com/bytecodealliance/wasm-tools) include

To compose a component with the components it directly depends on, run:

```
```sh
wasm-tools compose path/to/component.wasm -d path/to/dep1.wasm -d path/to/dep2.wasm -o composed.wasm
```

Expand Down
6 changes: 2 additions & 4 deletions component-model/src/creating-and-consuming/running.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ You can "run" a component by calling one of its exports. In some cases, this req
You must use a recent version of `wasmtime` ([`v14.0.0` or greater](https://github.com/bytecodealliance/wasmtime/releases)), as earlier releases of the `wasmtime` command line do not include component model support.

> If you build the `wasmtime` CLI from source, you must pass `--features component-model` to the build command.
To run your component, run:

```sh
wasmtime run --wasm component-model <path-to-wasm-file>
wasmtime run <path-to-wasm-file>
```

## Running components with custom exports
Expand All @@ -28,6 +26,6 @@ If you're writing a library-style component - that is, one that exports a custom

5. Compose your command component with your library component by running `wasm-tools compose <path/to/command.wasm> -d <path/to/library.wasm> -o main.wasm`.

6. Run the composed component using `wasmtime run --wasm component-model main.wasm`
6. Run the composed component using `wasmtime run main.wasm`

See [Composing Components](./composing.md) for more details.
1 change: 0 additions & 1 deletion component-model/src/implementations/jco.md

This file was deleted.

1 change: 0 additions & 1 deletion component-model/src/implementations/wasmtime.md

This file was deleted.

21 changes: 15 additions & 6 deletions component-model/src/language-support/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,26 @@
[`jco`](https://github.com/bytecodealliance/jco) is a fully native JS tool for working with the
emerging WebAssembly Components specification in JavaScript.

### Building a Component with `jco`
## Building a Component with `jco`

A component can be created from a JS module using `jco componentize`. First, install `jco` and
`componentize-js`:
A component can be created from a JS module using `jco componentize`. First, install `jco` and `componentize-js`:

```sh
$ npm install @bytecodealliance/jco
$ npm install @bytecodealliance/componentize-js
```

Create a JavaScript module that implements the `add` function in [`add.wit`](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit):
Next, create or download the WIT world you would like to target. For this example we will use an [`example`
world](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit) with an `add` function:

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

Create a JavaScript module that implements the `add` function in the `example` world.

```js
export function add(x, y) {
Expand All @@ -24,7 +33,7 @@ export function add(x, y) {
Now, use `jco` to create a component from the JS module:

```sh
$ jco componentize add.js --wit add.wit -n example -o add.wasm
$ jco componentize add.js --wit add.wit --world-name example --out add.wasm
OK Successfully written add.wasm with imports ().
```

Expand All @@ -36,7 +45,7 @@ $ cargo run --release -- 1 2 ../path/to/add.wasm
1 + 2 = 3
```

### Running a Component from JavaScript Applications
## Running a Component from JavaScript Applications

As the JavaScript runtime cannot yet execute Wasm components, a component must be transpiled into
JavaScript and a core module and then executed. `jco` automates this transpilation:
Expand Down
114 changes: 86 additions & 28 deletions component-model/src/language-support/python.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,51 @@
# Python Tooling

### Building a Component with `componentize-py`
## Building a Component with `componentize-py`

[`componentize-py`](https://github.com/dicej/componentize-py) is a tool that converts a Python
application to a WebAssembly component.

Create a Python program that implements the `add` function in the [`example`
world](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit). Note that it imports the bindings that will be created by
`componentize-py`:
First, install [Python 3.10 or later](https://www.python.org/) and [pip](https://pypi.org/project/pip/) if you don't already have them. Then, install `componentize-py`:

```sh
$ cat<<EOT >> guest.py
pip install componentize-py
```

Next, create or download the WIT world you would like to target. For this example we will use an [`example`
world](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit) with an `add` function:

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

If you want to generate bindings produced for the WIT world (for an IDE or typechecker), you can generate them using the `bindings` subcommand. Specify the path to the WIT interface with the world you are targeting:

```sh
$ componentize-py --wit-path /path/to/examples/example-host/add.wit --world example bindings .
```

> Note: you do not need to generate the bindings in order to `componentize` in the next step. `componentize` will generate bindings on-the-fly and bundle them into the produced component.
You can see that bindings were created in an `example` package which contains an `Example` protocol with an `add` method that we can implement:

```sh
$ cat<<EOT >> app.py
import example
class Example(example.Example):
def add(x: int, y: int) -> int:
def add(self, x: int, y: int) -> int:
return x + y
EOT
```

[Install `componentize-py`](https://github.com/dicej/componentize-py#installing-from-pypi) and
generate a component from `guest.py`.
We now can compile our application to a Wasm component using the `componentize` subcommand:

```sh
$ pip install componentize-py
$ componentize-py -d /path/to/examples/example-host/add.wit -w example componentize guest -o add.wasm
$ componentize-py --wit-path /path/to/examples/example-host/add.wit --world example componentize app -o add.wasm
Component built successfully
```

Expand All @@ -36,41 +57,78 @@ $ cargo run --release -- 1 2 ../path/to/add.wasm
1 + 2 = 3
```

### Running components from Python Applications
See [`componentize-py`'s examples](https://github.com/bytecodealliance/componentize-py/tree/main/examples) to try out build HTTP, CLI, and TCP components from Python applications.


### Building a Component that Exports an Interface

The [sample `add.wit` file](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit) exports a function. However, to use your component from another component, it must export an interface. That being said, you rarely find WIT that does not contain an interface. (Most WITs you'll see in the wild do use interfaces; we've been simplifying by exporting a function.) Let's expand our example world to export an interface rather than directly export the function.

```wit
// add-interface.wit
package example:component;
interface add {
add: func(a: u32, b: u32) -> u32;
}
world example {
export add;
}
```

If you peek at the bindings, you'll notice that we now implement a class for the `add` interface rather than for the `example` world. This is a consistent pattern. As you export more interfaces from your world, you implement more classes. Our add example gets the slight update of:

Wasm components can also be invoked from Python applications. This walks through the tooling needed
to call the `app.wasm` component from the previous section from a Python application. First, install
`wasmtime-py`, being sure to use a version [this PR has
merged](https://github.com/bytecodealliance/wasmtime-py/pull/171) or working off that branch.
```py
# app.py
import example

class Add(example.Example):
def add(self, a: int, b: int) -> int:
return a + b
```

> Note: be sure to use at least Python 3.11
Once again, compile an application to a Wasm component using the `componentize` subcommand:

```sh
$ git clone https://github.com/dicej/wasmtime-py
$ (cd wasmtime-py && python ci/download-wasmtime.py && python ci/build-rust.py && pip install .)
$ componentize-py --wit-path add-interface.wit --world example componentize app -o add.wasm
Component built successfully
```

Now, generate the bindings to be able to call the component from a Python host application.
## Running components from Python Applications

Wasm components can also be invoked from Python applications. This walks through using tooling
to call the [`app.wasm` component from the examples](../../examples/example-host/add.wasm).

> Note: `wasmtime-py` does not currently support running components build with `componentize-py`. This is because `wasmtime-py` does not yet support [resources](../design/wit.md#resources), which components built with `componentize-py` always use, since `componentize-py` unconditionally imports most of the `wasi:cli` world.
First, install [Python 3.11 or later](https://www.python.org/) and [pip](https://pypi.org/project/pip/) if you don't already have them. Then, install [`wasmtime-py`](https://github.com/bytecodealliance/wasmtime-py):

```sh
$ python3 -m wasmtime.bindgen add.wasm --out-dir add
$ pip install wasmtime
```

The generated package `add` has all of the requisite exports/imports for the component and is
annotated with types to assist with type-checking and self-documentation as much as possible.
First, generate the bindings to be able to call the component from a Python host application.

```sh
# Get an add component that does not import the WASI CLI world
$ wget https://github.com/bytecodealliance/component-docs/raw/main/component-model/examples/example-host/add.wasm
$ python3 -m wasmtime.bindgen add.wasm --out-dir add
```

Now, create a Python program to run the component. Note that imports for WASI preview 2 are
explicitly set to null. This is because when creating a component from a Python module,
`componentize-py` pulls in extra WASI Preview 2 imports, even if they are not used by the component.
Currently, language toolchains are likely to pull in more than a component declares in WAT.
The generated package `add` has all of the requisite exports/imports for the
component and is annotated with types to assist with type-checking and
self-documentation as much as possible. Inside the package is a `Root` class
with an `add` function that calls the component's exported `add` function. We
can now write a Python program that calls `add`:

```py
from add import Root, RootImports
from add import Root
from wasmtime import Store

def main():
store = Store()
component = Root(store, RootImports(poll=None, monotonic_clock=None, wall_clock=None, streams=None, filesystem=None, random=None, environment=None, preopens=None, exit=None, stdin=None, stdout=None, stderr=None))
component = Root(store)
print("1 + 2 = ", component.add(store, 1, 2))

if __name__ == '__main__':
Expand Down
8 changes: 4 additions & 4 deletions component-model/src/language-support/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The application uses [`wasmtime`](https://github.com/bytecodealliance/wasmtime)
Rust bindings, bring in WASI worlds, and execute the component.

```sh
$ cd examples/add-host
$ cd examples/example-host
$ cargo run --release -- 1 2 ../add/target/wasm32-wasi/release/add.wasm
1 + 2 = 3
```
Expand Down Expand Up @@ -214,9 +214,9 @@ You can write Rust in this project, just as you normally would, including import
To run your command component:

```
```sh
cargo component build
wasmtime run --wasm component-model ./target/wasm32-wasi/debug/<name>.wasm
wasmtime run ./target/wasm32-wasi/debug/<name>.wasm
```

> **WARNING:** If your program prints to standard out or error, you may not see the printed output! Some versions of `wasmtime` have a bug where they don't flush output streams before exiting. To work around this, add a `std::thread::sleep()` with a 10 millisecond delay before exiting `main`.
Expand Down Expand Up @@ -272,6 +272,6 @@ fn main() {
6. Run the composed component:

```sh
$ wasmtime run --wasm component-model ./my-composed-command.wasm
$ wasmtime run ./my-composed-command.wasm
1 + 1 = 579 # might need to go back and do some work on the calculator implementation
```
6 changes: 4 additions & 2 deletions component-model/src/runtimes/wasmtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
[Wasmtime](https://github.com/bytecodealliance/wasmtime/) is the reference implementation of the Component Model. It supports running components that implement the [`wasi:cli/command` world](https://github.com/WebAssembly/wasi-cli/blob/main/wit/command.wit) and serving components the implement the [`wasi:http/proxy` world](https://github.com/WebAssembly/wasi-http/blob/main/wit/proxy.wit).

## Running command components with Wasmtime
To run a command component with wasmtime, execute:
To run a command component with Wasmtime, execute:

```sh
wasmtime run --wasm component-model <path-to-wasm-file>
wasmtime run <path-to-wasm-file>
```

> If you are using an older version of `wasmtime`, you may need to add the `--wasm component-model` flag to specify that you are running a component rather than a core module.
By default, Wasmtime denies the component access to all system resources. For example, the component cannot access the file system or environment variables. See the [Wasmtime guide](https://docs.wasmtime.dev/) for information on granting access, and for other Wasmtime features.

## Running HTTP components with Wasmtime
Expand Down
2 changes: 1 addition & 1 deletion component-model/src/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Now it all adds up! Run the final component with the `wasmtime` CLI, ensuring yo
the `wasmtime` command line do not include component model support.

```sh
wasmtime run --wasm component-model final.wasm 1 2 add
wasmtime run final.wasm 1 2 add
1 + 2 = 3
```

Expand Down

0 comments on commit 91ba47f

Please sign in to comment.