Build
The wash CLI includes a build
command that is used to build all application components. The wash build CLI reference page has more information on each of the command's flags. The rest of this page will focus on practical examples of using the wash build
command.
You can see the list of supported languages in the wasmcloud.toml specification. At the time of writing this guide, this included Rust and TinyGo. If a language is supported in the wasmcloud.toml specification, then you can build it simply with:
wash build
- Rust
- TinyGo
- TypeScript
- Python
- My Language Isn't Listed
In a Rust project, the wash build command encapsulates a few commands. You can always use the standard Rust toolchain and Bytecode Alliance tools to build your application components. However, the wash build command will automatically use the necessary tools and build your component for you. Under the hood, the wash build command will run the following commands:
# Fetch wit dependencies
wkg wit fetch
# Build the Wasm module
cargo build --release --target wasm32-wasi
# Create a Wasm component from the Wasm module by using the wasmtime adapter
wasm-tools component new ./target/wasm32-wasi/release/module.wasm -o ./build/component.wasm --adapt ./wasi_snapshot_preview1.wasm
# Sign the Wasm component with your generated keys, using information in wasmcloud.toml
wash claims sign ./build/component.wasm --destination ./build/component_s.wasm
In a TinyGo project, the wash build command encapsulates a few commands. You can always use the standard Go and TinyGo toolchain and Bytecode Alliance tools to build your application components. However, the wash build command will automatically use the necessary tools and build your component for you. Under the hood, the wash build command will run the following commands:
# Fetch wit dependencies
wkg wit fetch
# Generate the types and bindings for the Wasm module
go generate
# Build the Wasm module
tinygo build -o ./build/module.wasm -target wasm32-wasi -scheduler none -no-debug .
# Embed the component wit metadata into the module
wasm-tools component embed wit ./build/module.wasm > ./build/embed.wasm
# Create a Wasm component from the embedded Wasm module by using the wasmtime adapter
wasm-tools component new ./build/embed.wasm -o ./build/component.wasm --adapt ./wasi_snapshot_preview1.wasm
# Sign the Wasm component with your generated keys, using information in wasmcloud.toml
wash claims sign ./build/component.wasm --destination ./build/component_s.wasm
# Remove temporarily created files
rm ./build/embed.wasm ./build/module.wasm
In a TypeScript project, the wash build command must be overridden in the wasmcloud.toml component section to use external tools. TypeScript builds require an npm installation and, after running npm install
, use ComponentizeJS to compile transpiled JavaScript code into a WebAssembly Component.
[component]
build_command = "npm run build"
In our quickstart example, wash build
runs a few commands for you in order to turn TypeScript code into a WebAssembly component:
# Fetch wit dependencies
wkg wit fetch
# You must run `npm install` first
npm install
# Transpile TypeScript code to JavaScript
tsc
# Componentize JavaScript code
jco componentize -w wit -o dist/index.wasm dist/index.js
# Sign the Wasm component with your generated keys, using information in wasmcloud.toml
wash build --sign-only --config-path wasmcloud.toml
In a Python project, the wash build command must be overridden in the wasmcloud.toml component section to use external tools. Python builds require a Python, pip installation and a componentize-py to compile Python code into a WebAssembly Component.
[component]
build_command = "componentize-py -d ./wit -w hello componentize app -o build/http_hello_world.wasm"
In our quickstart example, wash build
runs a few commands for you in order to turn Python code into a WebAssembly component:
# Fetch wit dependencies
wkg wit fetch
# Componentize Python code into a WebAssembly Component
componentize-py -d ./wit -w hello componentize app -o build/http_hello_world.wasm
# Sign the Wasm component with your generated keys, using information in wasmcloud.toml
wash build --sign-only --config-path wasmcloud.toml
wash build
has an escape hatch in the wasmcloud.toml
specification which will let you specify your own build command for languages that we don't have official support for. For example, following the ComponentizeJS example to build a JavaScript Component, you can set up your wasmcloud.toml
file like so:
name = "componentize-js"
language = "rust"
type = "component"
[component]
claims = ["wasmcloud:httpserver"]
build_command = "node componentize.mjs"
build_artifact = "hello.component.wasm"
destination = "hello_s.component.wasm"
Overriding the build_command
allows you to use an external script or command to build the component, then specifying where the build_artifact
is (wherever the component should be after the build command completes) lets wash
still sign the component using your generated keys and information in the wasmcloud.toml
file. Note that this command does not have full support for environment variables or multiple commands and should be in the form of "command arg1 arg2 arg...". It's recommended to use an external script to handle more complex build commands.
Interface dependencies and wash build
You may have noticed that one of the commands that wash build
runs for you is the equivalent of wkg wit fetch
. wkg
is a CLI tool provided by the ByteCode Alliance as part of the Wasm package tooling project. It is meant to be a standard set of configuration and tooling that can be used across all languages. wash
is directly integrated into this tooling with some additional helpers to make it automatically aware of wasmcloud
namespaced interfaces. If you use wkg
, you will be using the same configuration and lock files that wash
uses. The tooling works by reading the specified world in your wit files and downloading the appropriate dependencies automatically into the wit/deps
directory. As such, in most cases you should add wit/deps
to your .gitignore
file and commit the generated wkg.lock
file.
Without any additional configuration, wash
can download dependencies from the following namespaces (i.e. the wasi
in wasi:http@0.2.1
):
wasi
wasmcloud
wrpc
ba
So in most basic cases, all of this dependency fetching and management should be fairly transparent! However, as your usage of Wasm grows, you are likely to use dependencies that are not in the above namespaces (such as internal registries or other remappings). Also, if you plan to publish any custom interfaces, you will need to configure your registry with credentials.
Please note the configuration format is subject to change, including some additional override configurations options within the wasmcloud.toml
file. Things should be backwards compatible, but be aware that things may change (and will likely be simpler)!
The default configuration file for wash
is located inside of the standard configuration directory at ~/.wash/package_config.toml
.
Below is an extremely simple configuration showing the basics of a file that can be used to configure wkg
to download and publish dependencies to/from a private registry. For more complete information on the configuration options, see the Wasm package tooling documentation.
[namespace_registries]
# The namespace maps to a configuration that tells the client where to download dependencies from.
# If you are running a heavily used and/or large registry, see https://github.com/bytecodealliance/wasm-pkg-tools#well-known-metadata
# for more information on how to configure a well-known metadata file, which simplifies this configuration section.
custom = { registry = "custom", metadata = { preferredProtocol = "oci", "oci" = { registry = "ghcr.io", namespacePrefix = "myorg/interfaces/" } } }
# The registry section is used to configure the client to authenticate to the registry. The name
# "custom" must match the `registry` key in the namespace_registries section.
[registry."custom".oci]
auth = { username = "open", password = "sesame" }
With the above configuration, if a package named custom:regex@0.1.0
is found, it will attempt to download it from ghcr.io/myorg/interfaces/custom/regex:0.1.0
, using the credentials provided in the auth
section (if needed). If the registry is public, you can omit the registry
section at the bottom entirely.
Migrating from wit-deps
Older versions of wash
required a separate step using a wit-deps
tool to download dependencies. This is no longer necessary with the newest versions of wash
. To preserve backwards compatibility, if a deps.toml
file is found in the wit
directory of the project, wash
will not fetch dependencies for you. To migrate to the new deps management, simply remove the deps.toml
file and run wash build
again. wash build
will automatically remove all the old dependencies and download the new ones into your wit/deps
directory.
If you are using some of the provided wrpc interfaces like wrpc:blobstore
, you will need to continue using wit-deps
. This is due to an issue where some of the wrpc interfaces use syntax that is not yet available in the main WIT parser (but will be when WASI 0.3 is released) which causes the dependency resolution to fail.