Dependencies
# Build the CLI
cargo build --release --manifest-path tools/moon-component/Cargo.toml
# Add to PATH (optional)
export PATH="$PWD/tools/moon-component/target/release:$PATH"# Create a new component project
moon-component new my-component
# Or initialize in existing MoonBit project
moon-component init
# Build component (generate + build + componentize)
moon-component component wit/world.wit -o my-component.wasm --releasemoon-component new hello-world
cd hello-world
moon-component component wit/world.wit -o hello.wasm --releasemoon-component generate wit/world.wit -o ./component -p my/projectmoon-component component wit/world.wit -o output.wasm --releasemoon build --target wasm --release
moon-component componentize target/wasm/release/build/main/main.wasm \
--wit-dir wit -o component.wasm# Plug library.wasm exports into app.wasm imports
moon-component plug app.wasm library.wasm -o composed.wasm
# Multiple plugs
moon-component plug app.wasm lib1.wasm lib2.wasm -o composed.wasmmoon-component compose composition.wac -o composed.wasmpackage example:composed;
let app = new app:component { ... };
let lib = new lib:component { ... };
// Wire lib exports to app imports
let composed = new app { api: lib.api };
export composed...;# Bundle using moon-component.toml
moon-component bundle
# Custom config file
moon-component bundle -c my-config.toml
# Only build components, don't compose
moon-component bundle --build-only
# Preview generated WAC without executing
moon-component bundle --dry-run[bundle]
name = "my/app"
output = "dist/app.wasm"
entry = "apps/main/component"
# External imports (left unresolved for runtime)
externals = ["wasi:io/*", "wasi:cli/*"]
# Optional: use explicit WAC file instead of auto-generation
# wac = "custom.wac"
[dependencies]
"mizchi:flatbuffers" = { path = "libs/flatbuffers/component" }
"mizchi:json" = { path = "libs/json/component" }
[build]
target = "wasm"
release = truepackage my:app:composed;
let mizchi_flatbuffers = new mizchi:flatbuffers {};
let mizchi_json = new mizchi:json {};
let entry = new entry:component {
"mizchi:flatbuffers": mizchi_flatbuffers."mizchi:flatbuffers",
"mizchi:json": mizchi_json."mizchi:json",
};
export entry...;monorepo/
├── moon-component.toml # Bundle config
├── libs/
│ ├── flatbuffers/component/ # flatbuffers component
│ └── json/component/ # json component
└── apps/
└── main/component/ # app that imports libs# One command to build and compose everything
moon-component bundle# Build each component manually
moon-component component libs/flatbuffers/wit/world.wit -o flatbuffers.wasm
moon-component component apps/main/wit/world.wit -o main.wasm
# Plug libraries into app
moon-component plug main.wasm flatbuffers.wasm -o app.wasm
# Or use WAC file for complex compositions
moon-component compose composition.wac -o app.wasmcomponent/
├── moon.mod.json
├── wit/
│ └── world.wit # WIT definition
├── gen/ # Generated code (regenerated)
│ └── cabi/
│ ├── moon.pkg.json
│ └── cabi.mbt # Canonical ABI helpers
└── impl/ # Implementation (preserved)
├── moon.pkg.json # is-main: true
├── bindings.mbt # Generated FFI glue (regenerated)
└── impl.mbt # User implementation (stub, preserved)| WIT Type | MoonBit Type | Notes |
|---|---|---|
| bool | Bool | |
| u8 | Byte | |
| u16, u32 | UInt | |
| u64 | UInt64 | |
| s8, s16, s32 | Int | |
| s64 | Int64 | |
| f32 | Float | |
| f64 | Double | |
| char | Char | |
| string | String | UTF-8 encoded |
| list<T> | Array[T] | |
| option<T> | T? | |
| result<T, E> | Result[T, E] | |
| tuple<...> | (T1, T2, ...) | |
| record | struct | |
| variant | enum | |
| enum | enum | With from_ordinal/ordinal |
| flags | struct (bitmask) | With from_bits/to_bits |
| resource | struct(Int) | Handle-based (experimental) |
interface blob-store {
resource blob {
constructor(data: list<u8>);
size: func() -> u32;
read: func(offset: u32, len: u32) -> list<u8>;
}
create-blob: func(data: list<u8>) -> own<blob>;
get-blob-size: func(b: borrow<blob>) -> u32;
}// Resource type (handle)
///|
pub(all) struct Blob(Int) derive(Show, Eq)
// Exported functions with normalized names
///|
pub fn blob_new(data : Array[Byte]) -> Blob // [constructor]blob
pub fn blob_size(this : Blob) -> UInt // [method]blob.size
pub fn blob_read(this : Blob, offset : UInt, len : UInt) -> Array[Byte]
pub fn create_blob(data : Array[Byte]) -> Blob
pub fn get_blob_size(b : Blob) -> UInt// Handle table for resource storage
///|
let blob_table : Ref[Array[Array[Byte]]] = { val: [] }
///|
fn allocate_blob(data : Array[Byte]) -> @exports.Blob {
let handle = blob_table.val.length()
blob_table.val.push(data)
@exports.Blob(handle)
}
///|
fn get_blob(handle : @exports.Blob) -> Array[Byte] {
blob_table.val[handle.0]
}| Host | Language | Test Level | Notes |
|---|---|---|---|
| examples/tests/rust-host | Rust | Component | Full canonical ABI testing via wasmtime |
| examples/tests/swift-host | Swift | Core Wasm | Runtime testing via WasmKit (macOS 14+) |
| examples/tests/scala-host | Scala | Core Wasm | Runtime testing via Chicory (JDK 11+) |
| examples/tests/zig-host | Zig | Core Wasm | Binary format validation (export verification) |
| examples/tests/jco-host | JavaScript | Component | Node.js testing via jco transpiler |
# Run all integration tests (Rust, Zig, Swift)
just test-integration
# Run all integration tests including Scala and jco (requires sbt, pnpm)
just test-integration-all
# Run individual host tests
just test-rust-host
just test-swift-host
just test-scala-host
just test-zig-host
just test-jco-hostDependencies