컴포넌트 모델

WebAssembly Component Model

Overview

The WebAssembly Component Model provides a standardized way to create composable, portable WebAssembly components with high-level interface definitions.

What is the Component Model?

The Component Model is a proposal for WebAssembly that adds:

  • Interface definitions (WIT - WebAssembly Interface Types)
  • Component composition
  • Strong typing across module boundaries
  • Language-agnostic interfaces

Vais Support

Vais supports compiling to WebAssembly components that can:

  • Export functions with typed interfaces
  • Import functions from other components
  • Compose with components from other languages
  • Run in sandboxed environments

Architecture

┌─────────────────────────────────────────────────────────────┐
│              Vais WebAssembly Component                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────────┐      ┌──────────────┐                    │
│  │ Vais Source  │─────▶│  LLVM WASM   │                    │
│  │   (.vais)    │      │   Backend    │                    │
│  └──────────────┘      └──────┬───────┘                    │
│                               │                             │
│                               ▼                             │
│                        ┌─────────────┐                      │
│                        │ Core WASM   │                      │
│                        │  Module     │                      │
│                        └──────┬──────┘                      │
│                               │                             │
│                               ▼                             │
│                        ┌─────────────┐                      │
│                        │  Component  │                      │
│                        │  Adapter    │                      │
│                        └──────┬──────┘                      │
│                               │                             │
│                               ▼                             │
│                        ┌─────────────┐                      │
│                        │ WASM        │                      │
│                        │ Component   │                      │
│                        └─────────────┘                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

WIT Interface Definitions

Example Interface

calculator.wit:

package vais:calculator

interface calculate {
    add: func(a: s32, b: s32) -> s32
    subtract: func(a: s32, b: s32) -> s32
    multiply: func(a: s32, b: s32) -> s32
    divide: func(a: s32, b: s32) -> result<s32, string>
}

world calculator {
    export calculate
}

Vais Implementation

calculator.vais:

# Export functions matching WIT interface
F add(a: i32, b: i32) -> i32 {
    a + b
}

F subtract(a: i32, b: i32) -> i32 {
    a - b
}

F multiply(a: i32, b: i32) -> i32 {
    a * b
}

F divide(a: i32, b: i32) -> Result<i32, String> {
    I b == 0 {
        R Err("Division by zero")
    }
    Ok(a / b)
}

Type Mappings

WIT to Vais Types

WIT TypeVais TypeDescription
s8, s16, s32, s64i8, i16, i32, i64Signed integers
u8, u16, u32, u64u8, u16, u32, u64Unsigned integers
f32, f64f32, f64Floating point
charcharUnicode character
stringStringUTF-8 string
boolboolBoolean
listVecDynamic array
optionOptionalOptional value
result<T, E>Result<T, E>Result type
tuple<A, B>(A, B)Tuple
recordstructRecord type
variantenumVariant type

Records (Structs)

WIT:

record point {
    x: f64,
    y: f64,
}

Vais:

S Point {
    x: f64,
    y: f64,
}

Variants (Enums)

WIT:

variant color {
    red,
    green,
    blue,
    custom(u8, u8, u8),
}

Vais:

E Color {
    Red,
    Green,
    Blue,
    Custom(u8, u8, u8),
}

Building Components

Compile to WASM Component

vaisc build calculator.vais --target wasm32-wasi --component

This generates:

  • calculator.wasm - Core WebAssembly module
  • calculator.component.wasm - Component with adapters

Using Component Tooling

# Inspect component
wasm-tools component wit calculator.component.wasm

# Validate component
wasm-tools validate calculator.component.wasm

# Compose components
wasm-tools compose -o composed.wasm calculator.component.wasm ui.component.wasm

Component Composition

Importing Components

WIT:

package vais:app

interface app {
    import vais:calculator/calculate

    run: func() -> s32
}

Vais:

# Import calculator component
import calculator::{ add, multiply }

F run() -> i32 {
    x := add(10, 20)
    y := multiply(x, 2)
    y
}

Composing Multiple Components

# Build calculator component
vaisc build calculator.vais --component -o calculator.wasm

# Build app component
vaisc build app.vais --component -o app.wasm

# Compose them
wasm-tools compose \
    -d calculator.wasm \
    -o composed.wasm \
    app.wasm

Runtime Environments

WASI Preview 2

Vais components can run in WASI Preview 2 environments:

# Run with wasmtime
wasmtime run calculator.component.wasm

# Run with wasmer
wasmer run calculator.component.wasm

Browser Environments

Components can run in browsers with polyfills:

import { instantiate } from './calculator.component.js';

const calculator = await instantiate();
const result = calculator.add(5, 3);
console.log('5 + 3 =', result);

Vais Playground

The web playground uses WASM components:

  • Client-side compilation
  • Sandboxed execution
  • Cross-language composition

Advanced Features

Resource Types

WIT:

resource file {
    constructor(path: string)
    read: func() -> result<string, string>
    write: func(data: string) -> result<unit, string>
}

Vais:

S File {
    handle: *void,
}

impl File {
    F new(path: String) -> File {
        # Implementation
    }

    F read(self: *File) -> Result<String, String> {
        # Implementation
    }

    F write(self: *File, data: String) -> Result<(), String> {
        # Implementation
    }
}

Async Functions

WIT:

interface async-io {
    fetch: func(url: string) -> future<result<string, string>>
}

Vais:

A F fetch(url: String) -> Result<String, String> {
    # Async implementation
}

Security and Sandboxing

Capability-Based Security

Components can only access what they import:

world secure-app {
    import wasi:filesystem/types
    import wasi:sockets/tcp

    export run
}

Resource Limits

# Limit memory and CPU
wasmtime run --max-memory 10M --max-wasm-stack 100K component.wasm

Performance

Size Optimization

# Optimize component size
wasm-opt -Os -o optimized.wasm calculator.wasm

# Strip debug info
wasm-strip optimized.wasm

Benchmark Results

Typical performance:

  • Instantiation: 1-10ms
  • Function calls: Near-native (within 10%)
  • Memory overhead: ~1-2MB per component

Debugging

Component Inspector

# View component structure
wasm-tools component wit calculator.component.wasm

# Dump imports/exports
wasm-objdump -x calculator.component.wasm

Debugging in Browser

Use browser DevTools with source maps:

vaisc build app.vais --component --source-map

Best Practices

1. Design Clear Interfaces

Define minimal, focused interfaces:

interface math {
    // Good: focused interface
    add: func(a: s32, b: s32) -> s32
    subtract: func(a: s32, b: s32) -> s32
}

interface utils {
    // Avoid: too broad
    do-everything: func(input: string) -> string
}

2. Use Appropriate Types

Choose the right type for data:

// Good: specific types
record user {
    id: u64,
    name: string,
    email: string,
}

// Avoid: stringly-typed
record user-bad {
    data: string,
}

3. Handle Errors Properly

Use Result types for fallible operations:

F parse_number(s: String) -> Result<i32, String> {
    # Return Ok or Err
}

4. Minimize Component Size

  • Use only needed imports
  • Enable optimization flags
  • Strip debug information in production

Tools and Ecosystem

Component Toolchain

  • wasm-tools - Component manipulation
  • wit-bindgen - Generate bindings
  • wasmtime - Component runtime
  • cargo-component - Rust components

Vais Integration

# Generate WIT from Vais
vaisc wit-export module.vais -o interface.wit

# Generate Vais from WIT
vaisc wit-import interface.wit -o bindings.vais

Examples

See the following examples:

  • examples/wasm_component_simple.vais - Basic component
  • examples/wasm_component_compose.vais - Component composition
  • examples/wasm_component_async.vais - Async components

Further Reading

  • Implementation: WASM_COMPONENT_IMPLEMENTATION.md
  • WASI Docs: https://wasi.dev/
  • Component Model Proposal: https://github.com/WebAssembly/component-model

Status

WebAssembly Component Model support is production-ready with full tooling integration.