You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: component-model/examples/tutorial/README.md
+61-6Lines changed: 61 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,6 @@ world adder {
18
18
}
19
19
```
20
20
21
-
22
21
```wit calculator
23
22
package docs:calculator@0.1.0;
24
23
@@ -44,18 +43,74 @@ To expand the exercise to add more components, add another operator world, expan
44
43
45
44
## Building and running the example
46
45
47
-
To compose a calculator component with an add operator, run the following:
46
+
Use [`cargo-component`](https://github.com/bytecodealliance/cargo-component) and [`wac`](https://github.com/bytecodealliance/wac) to build and compose the calculator component.
`wac plug` is a convenience to achieve a common pattern in component compositions like above. However, composition can be arbitrarily complicated. In cases where `wac plug` is not sufficient, the WAC language can give us the ability to create arbitrarily complex compositions. To get more experience using the WAC language, let's look at how we could use it to create our composition.
66
+
67
+
`wac` can compose local components and components hosted in registries. To compose local components, first move the components to a `deps` folder, the default location in which `wac` looks for local components. `wac` infers the subpath to components from the package name of components defined in a WAC file. For example, if the instantiation expression for the adder component in the WAC file is `new docs:adder-impl{}`, the local component is expected to have the following path `deps/docs/adder-impl.wasm`. With this in mind, let's move all out components to a `deps/docs` folder and rename to ease clarifying WAC concepts.
Now we are ready to construct a WAC file to define our composition. Ours instantiates our three components, declaring
77
+
which components satisfy each of their imports. It ends with an export of the `wasi:cli/run` interface from the command component. This is the export that the Wasmtime CLI requires in order to execute the final component on the command line.
78
+
79
+
```wac
80
+
// Provide a package name for the resulting composition
81
+
package example:composition;
82
+
83
+
// Instantiate the adder-impl component that implements the adder world.
84
+
// We are giving this instance the local name `adder-instance`.
85
+
let adder-instance = new docs:adder-impl { };
86
+
87
+
// Instantiate the calculator-impl component that implements the calculator world.
88
+
// In the `new` expression, specify the source of the `add` import to be `adder-instance`'s `add` export.
89
+
let calculator-instance = new docs:calculator-impl { add: adder-instance.add };
90
+
91
+
// Instantiate a command-impl component that implements the app world.
92
+
// The command component might import other interfaces, such as WASI interfaces, but we want to leave
93
+
// those as imports in the final component, so supply `...` to allow those other imports to remain unresolved.
94
+
// The command's exports (in this case, `wasi:cli/run`) remain unaffected in the resulting instance.
95
+
let command-instance = new docs:command-impl { calculate: calculator-instance.calculate,... };
96
+
97
+
// Export the `wasi:cli/run` interface from the command instance
98
+
// This could also have been expressed using the postfix access expression `command-instance.run`
99
+
export command-instance["wasi:cli/run@0.2.0"];
100
+
```
101
+
102
+
Now, perform your composition by passing the WAC file to `wac compose`.
103
+
104
+
```sh
105
+
wac compose composition.wac -o final.wasm
106
+
```
107
+
108
+
> Note, instead of moving all the components to a `deps/docs` directory, you can pass the paths to the components inline
@@ -49,21 +51,54 @@ Component composition tools are in their early stages right now. Here are some
49
51
* Composition is asymmetrical. It is not just "gluing components together" - it takes a primary component which has imports, and satisfies its imports using dependency components. For example, composing an implementation of `validator` with an implementation of `regex` makes sense because `validator` has a dependency that `regex` can satisfy; doing it the other way round doesn't work, because `regex` doesn't have any dependencies, let alone ones that `validator` can satisfy.
50
52
* Composition cares about interface versions, and current tools are inconsistent about when they infer or inject versions. For example, if a Rust component exports `test:mypackage`, `cargo component build` will decorate this with the crate version, e.g. `test:mypackage@0.1.0`. If another Rust component _imports_ an interface from `test:mypackage`, that won't match `test:mypackage@0.1.0`. You can use [`wasm-tools component wit`](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component) to view the imports and exports embedded in the `.wasm` files and check whether they match up.
51
53
52
-
## Composing components with `wasm-tools`
54
+
## Composing components with WAC
55
+
56
+
You can use the [WAC](https://github.com/bytecodealliance/wac) CLI to compose components at the command line.
53
57
54
-
The [`wasm-tools` suite](https://github.com/bytecodealliance/wasm-tools) includes a `compose` command which can be used to compose components at the command line.
58
+
To perform quick and simple compositions, use the `wac plug` command. `wac plug` satisfies the import of a "socket" component by plugging a "plug" component's export into the socket. For example, a component that implements the [`validator` world above](#what-is-composition) needs to satisfy it's `match` import. It is a socket. While a component that implements the `regex` world, exports the `match` interface, and can be used as a plug. `wac plug` can plug a regex component's export into the validator component's import, creating a resultant composition:
Here `component.wasm` is the component that imports interfaces from `dep1.wasm` and `dep2.wasm`, which export them. The composed component, with those dependencies satisfied and tucked away inside it, is saved to `composed.wasm`.
63
71
64
-
> This syntax doesn't cover transitive dependencies. If, for example, `dep1.wasm` has unsatisfied imports that you want to satisfy from `dep3.wasm`, you'll need to use a [configuration file](https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wasm-compose/CONFIG.md). (Or you can compose `dep1.wasm` with `dep3.wasm` first, then refer to that composed component instead of `dep1.wasm`. This doesn't scale to lots of transitive dependencies though!)
72
+
The `plug` syntax doesn't cover transitive dependencies. If, for example, `dep1.wasm` has unsatisfied imports that you want to satisfy from `dep3.wasm`, you'd need to be deliberate about the order of your composition. You could compose `dep1.wasm` with `dep3.wasm` first, then refer to that composed component instead of `dep1.wasm`. However, this doesn't scale to lots of transitive dependencies, which is why the WAC language was created.
73
+
74
+
### Advanced composition with the WAC language
75
+
76
+
`wac plug` is a convenience to achieve a common pattern in component compositions like above. However, composition can be arbitrarily complicated. In cases where `wac plug` is not sufficient, the [WAC language](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) can give us the ability to create arbitrarily complex compositions.
77
+
78
+
In a WAC file, you use the WAC language to describe a composition. For example, the following is a WAC file that could be used to create that validator component from [earlier](#what-is-composition).
79
+
80
+
```
81
+
//composition.wac
82
+
// Provide a package name for the resulting composition
83
+
package docs:composition;
84
+
85
+
// Instantiate the regex-impl component that implements the `regex` world. Bind this instance's exports to the local name `regex`.
86
+
let regex = new docs:regex-impl { };
87
+
88
+
// Instantiate the validator-impl component which implements the `validator` world and imports the match interface from the regex component.
89
+
let validator = new docs:validator-impl { match: regex.match, ... };
90
+
91
+
// Export all remaining exports of the validator instance
92
+
export validator...;
93
+
```
94
+
95
+
Then, `wac compose` can be used to compose the components, passing in the paths to the components. Alternatively, you can place the components in a `deps` directory with an expected structure, and in the near future, you will be able to pull in components from registries. See the [`wac` documentation](https://github.com/bytecodealliance/wac) for more details.
For full information about `wasm-tools compose` including how to configure more advanced scenarios, see [the `wasm-tools compose` documentation](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-compose).
101
+
For an in depth description about how to use the wac tool, you can check out the [wac language index](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) and [examples](https://github.com/bytecodealliance/wac/tree/main/examples).
0 commit comments