Repository navigation
Add Dart documentation #377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,139 @@ | ||||||||||||||||||
| # Dart Tooling | ||||||||||||||||||
|
|
||||||||||||||||||
| > [!WARNING] | ||||||||||||||||||
| > Compiling Dart to non-web WebAssembly targets is experimental. | ||||||||||||||||||
| > This guide requires Dart version `3.14.0-251.0.dev` or later. | ||||||||||||||||||
|
|
||||||||||||||||||
| WebAssembly components in Dart can be built with the [wasm_tools package](https://github.com/simolus3/wasm.dart/) on pub.dev. | ||||||||||||||||||
|
|
||||||||||||||||||
| This guide walks through building a Dart component that implements | ||||||||||||||||||
| the `adder` world defined in the [`adder/world.wit` package][docs-adder]. | ||||||||||||||||||
| The component will implement the `adder` world, which contains an `add` interface with an `add` function. | ||||||||||||||||||
|
|
||||||||||||||||||
| Keep in mind that this is a basic intro. For more examples, please see the [dart-samples][examples] | ||||||||||||||||||
| from the `wasm_tools` package or TODO: running a component. | ||||||||||||||||||
|
|
||||||||||||||||||
| If you still have questions, feel free to open an issue on [the repository][wasm_tools] | ||||||||||||||||||
| or reach out on [Zulip][chat]. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## 1. Create your Dart project | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to include a section about tooling/setup here, and that would be a good place for the warning to go |
||||||||||||||||||
|
|
||||||||||||||||||
| Begin by creating a fresh Dart project: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```sh | ||||||||||||||||||
| dart create -t cli dart_wasm_adder | ||||||||||||||||||
| cd dart_wasm_adder | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ## 2. Install the tools | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Something like this? |
||||||||||||||||||
|
|
||||||||||||||||||
| All tools requires to create WebAssembly components from Dart can be installed via pub: | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Maybe it's more normal to refer to it as just "pub", but in that case I think even |
||||||||||||||||||
|
|
||||||||||||||||||
| ```sh | ||||||||||||||||||
| dart pub add wasm_components dev:wasm_tools | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| The `wasm_components` package provides runtime support for component models | ||||||||||||||||||
| (like an allocator or async task management), while `wasm_tools` contains `witgen` | ||||||||||||||||||
| and tools to compile Dart to components. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## 3. Generate bindings for the Wasm component | ||||||||||||||||||
|
|
||||||||||||||||||
| Since we will be implementing the [`adder` world][docs-adder], we can copy the WIT to our project. | ||||||||||||||||||
| Create a file named `adder.wit` and paste the following code into it: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```wit | ||||||||||||||||||
| {{#include ../../../examples/tutorial/wit/adder/world.wit}} | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Generate Dart code and required metadata for the compiler with | ||||||||||||||||||
|
|
||||||||||||||||||
| ```sh | ||||||||||||||||||
| dart run wasm_tools witgen -i adder.wit | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| This generates: | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be a good place to maybe add a blub about what It might also be nice if where we introduce
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||
|
|
||||||||||||||||||
| - `lib/src/components/docs_adder.dart` containing interfaces (only `add` in this example). | ||||||||||||||||||
| - `lib/src/components/docs_adder_adder.dart` containing bindings for the `adder` world. | ||||||||||||||||||
| - `lib/src/components/docs_adder_adder.json` containing metadata used to turn WebAssembly | ||||||||||||||||||
| modules emitted by `dart2wasm` into components. | ||||||||||||||||||
|
|
||||||||||||||||||
| The JSON file describe which component imports and exports a Dart program needs. | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
| The toolchain reads it via [link hooks]. All packages defining component imports | ||||||||||||||||||
| or exports need one, including the `dart_wasm_adder` package. Create a | ||||||||||||||||||
| `hook/link.dart` file with these contents: | ||||||||||||||||||
|
Comment on lines
+63
to
+65
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Not sure what these are called normally "link hook script" or "link hook", but fine with either. |
||||||||||||||||||
|
|
||||||||||||||||||
| ```dart | ||||||||||||||||||
| import 'dart:convert'; | ||||||||||||||||||
| import 'dart:io'; | ||||||||||||||||||
|
|
||||||||||||||||||
| import 'package:hooks/hooks.dart'; | ||||||||||||||||||
| import 'package:wasm_tools/hooks.dart'; | ||||||||||||||||||
|
|
||||||||||||||||||
| void main(List<String> args) => link(args, (input, output) async { | ||||||||||||||||||
| if (input.config.buildWasmComponent) { | ||||||||||||||||||
| final abi = input.packageRoot.resolve('lib/src/components/docs_adder_adder.json'); | ||||||||||||||||||
|
|
||||||||||||||||||
| output.dependencies.add(abi); | ||||||||||||||||||
| output.assets.webAssemblyComponents.add( | ||||||||||||||||||
| WasmComponentAsset( | ||||||||||||||||||
| encoded: json.decode( | ||||||||||||||||||
| File(abi.toFilePath()).readAsStringSync(), | ||||||||||||||||||
| ) as Map<String, Object?>, | ||||||||||||||||||
| ), | ||||||||||||||||||
| ); | ||||||||||||||||||
| } | ||||||||||||||||||
| }); | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ## 4. Implement the `add` function | ||||||||||||||||||
|
|
||||||||||||||||||
| The generated `adderComponent` function is used to define this component: | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to be a little bit more explanatory here -- like "The |
||||||||||||||||||
| It receives imported interfaces as parameters (in this case, there aren't any) | ||||||||||||||||||
| and returns the exported interface. | ||||||||||||||||||
|
|
||||||||||||||||||
| For this example, replace `bin/dart_wasm_adder.dart` with: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```dart | ||||||||||||||||||
| import 'package:dart_wasm_adder/src/components/docs_adder.dart'; | ||||||||||||||||||
| import 'package:dart_wasm_adder/src/components/docs_adder_adder.dart'; | ||||||||||||||||||
|
|
||||||||||||||||||
| import 'package:wasm_components/wasm_components.dart'; | ||||||||||||||||||
|
|
||||||||||||||||||
| void main() { | ||||||||||||||||||
| adderComponent((_) => const _Add()); | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some comments might be nice here to explain what is happening/the mechanism here and how the generated code fits in with this user-provided code. For example, this section could be A section after the code block would also be fine. |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| final class const _Add() implements Add { | ||||||||||||||||||
| @override | ||||||||||||||||||
| int add({required int x, required int y}) { | ||||||||||||||||||
| return x + y; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ## 5. Testing the `add` component | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| With all generated bindings set up, the component can be compiled: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```sh | ||||||||||||||||||
| dart run wasm_tools compile bin/dart_wasm_adder.dart | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| This creates `bin/dart_wasm_adder.wasm`, a component we can invoke from the | ||||||||||||||||||
| CLI with [wasmtime]: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```console | ||||||||||||||||||
| $ wasmtime run --invoke 'add(1, 2)' bin/dart_wasm_adder.wasm | ||||||||||||||||||
| 3 | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| With this, we have successfully built and run a basic WebAssembly component with Dart 🎉 | ||||||||||||||||||
|
|
||||||||||||||||||
| [wasm_tools]: https://github.com/simolus3/wasm.dart/ | ||||||||||||||||||
| [examples]: https://github.com/simolus3/wasm.dart/tree/main/pkg/wasm_tools/example | ||||||||||||||||||
| [docs-adder]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/adder/world.wit | ||||||||||||||||||
| [chat]: https://bytecodealliance.zulipchat.com/#narrow/channel/394175-SIG-Guest-Languages/topic/Dart.20subgroup/with/614175797 | ||||||||||||||||||
| [link hooks]: https://dart.dev/tools/hooks | ||||||||||||||||||
| [wasmtime]: https://wasmtime.dev/ | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Creating Runnable Components (Dart) | ||
|
|
||
| > [!WARNING] | ||
| > Compiling Dart to non-web WebAssembly targets is experimental. | ||
| > This guide requires Dart version `3.14.0-251.0.dev` or later. | ||
|
|
||
| ## Creating a command component | ||
|
|
||
| A _command_ is a component with a specific export that allows it to be executed directly by `wasmtime` | ||
| (or other `wasi:cli` hosts). Ignoring the specifics of defining components in Dart, this is the | ||
| equivalent of running a plain Dart program with a `main()` function. | ||
|
|
||
| ### 1. Create a new Dart project | ||
|
|
||
| To create a command with Dart, start with a fresh Dart package: | ||
|
|
||
| ```sh | ||
| dart create -t cli dart_wasm_cli | ||
| ``` | ||
|
|
||
| To configure this package for WebAssembly components, add tooling dependencies. | ||
| Additionally, the `wasi` package provides generated bindings to WASI definitions, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This note about not needing to |
||
| meaning that running `dart run wasm_tools witgen` won't be necessary. | ||
|
|
||
| ```sh | ||
| dart pub add wasi wasm_components dev:wasm_tools | ||
| ``` | ||
|
|
||
| ### 2. Write the relevant Dart | ||
|
|
||
| The following code can be inserted into `bin/dart_wasm_cli.dart`: | ||
|
|
||
| ```dart | ||
| import 'dart:async'; | ||
| import 'dart:convert'; | ||
| import 'dart:typed_data'; | ||
|
|
||
| import 'package:wasi/cli/command.dart'; | ||
| import 'package:wasi/cli.dart'; | ||
| import 'package:wasm_components/wasm_components.dart'; | ||
|
|
||
| void main() { | ||
| commandComponent((imports) => _Run(imports.cliStdout)); | ||
| } | ||
|
|
||
| final class _Run(final Stdout stdout) implements Run { | ||
| @override | ||
| Future<Result<void, void>> run() async { | ||
| final out = StreamController<Uint8List>(); | ||
| final stdoutDone = stdout.writeViaStream(data: out.stream); | ||
|
|
||
| out.add(utf8.encode('Hello world!\n')); | ||
| out.close(); | ||
| await stdoutDone; | ||
|
|
||
| return const .ok(null); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Build the component | ||
|
|
||
| To build the component, use `wasm_tools compile`: | ||
|
|
||
| ```sh | ||
| dart run wasm_tools compile bin/dart_wasm_cli.dart | ||
| ``` | ||
|
|
||
| The [link hook] of the `wasi` package detects that this Dart program defines a | ||
| command component and configures the relevant imports and exports. | ||
| This allows the component to target `wasi:cli/command@0.3.0`. | ||
|
|
||
| ### 4. Run the component with `wasmtime` | ||
|
|
||
| To run your command component: | ||
|
|
||
| ```sh | ||
| wasmtime run bin/dart_wasm_cli.wasm | ||
| ``` | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: Expected output might be nice to include here |
||
| [link hook]: https://github.com/simolus3/wasm.dart/blob/ec9f801ebe258fc4c8dc0dceec35af8b9447627f/pkg/wasi/hook/link.dart#L17-L21 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: I think just pasting the WIT here (we can use a reference so the file stays in sync) would be easier than reading through this prose.