Building Wasm Components with JavaScript/TypeScript

This cookbook guide shows you how to build WebAssembly components using JavaScript or TypeScript that work with Wassette.

Quick Start

Prerequisites

  • Node.js (version 18 or later)
  • npm or yarn package manager

Install Tools

npm install -g @bytecodealliance/jco

Step-by-Step Guide

1. Create Your Project

mkdir my-component
cd my-component
npm init -y

2. Install Dependencies

{
  "type": "module",
  "dependencies": {
    "@bytecodealliance/componentize-js": "^0.18.1",
    "@bytecodealliance/jco": "^1.11.1"
  },
  "scripts": {
    "build:component": "jco componentize -w ./wit main.js -o component.wasm"
  }
}
npm install

3. Define Your Interface (WIT)

Create wit/world.wit:

package local:my-component;

interface calculator {
    add: func(a: s32, b: s32) -> s32;
    divide: func(a: f64, b: f64) -> result<f64, string>;
}

world calculator-component {
    export calculator;
}

4. Implement Your Component

Create main.js:

export const calculator = {
    add(a, b) {
        return a + b;
    },
    
    divide(a, b) {
        if (b === 0) {
            return { tag: "err", val: "Division by zero" };
        }
        return { tag: "ok", val: a / b };
    }
};

5. Build Your Component

# Basic build
jco componentize main.js --wit ./wit -o component.wasm

# Build with WASI dependencies
jco componentize main.js --wit ./wit -d http -d random -d stdio -o component.wasm

Common WASI dependencies:

  • http - HTTP client capabilities
  • random - Random number generation
  • stdio - Standard input/output
  • filesystem - File system access
  • clocks - Time and clock access

6. Test Your Component

wassette serve --sse --plugin-dir .

Complete Examples

Simple Time Server

wit/world.wit:

package local:time-server;

world time-server {
    export get-current-time: func() -> string;
}

main.js:

export function getCurrentTime() {
    return new Date().toISOString();
}

HTTP Weather Service

wit/world.wit:

package local:weather;

world weather-service {
    export get-weather: func(location: string) -> result<string, string>;
}

main.js:

import { fetch } from 'wasi:http/outgoing-handler';

export async function getWeather(location) {
    try {
        const response = await fetch(`https://api.weather.com/${location}`);
        const data = await response.json();
        return { tag: "ok", val: JSON.stringify(data) };
    } catch (error) {
        return { tag: "err", val: error.message };
    }
}

Error Handling

JavaScript components use WIT’s result type for error handling:

// Success
return { tag: "ok", val: resultValue };

// Error
return { tag: "err", val: "Error message" };

Using WASI Interfaces

HTTP Client

import { fetch } from 'wasi:http/outgoing-handler';

const response = await fetch('https://api.example.com/data');

Random Numbers

import { getRandomBytes } from 'wasi:random/random';

const bytes = getRandomBytes(16);

File System

import { read, write } from 'wasi:filesystem/types';

const content = await read('/path/to/file');
await write('/path/to/file', data);

Best Practices

  1. Use clear interface definitions - Make your WIT interfaces descriptive and well-documented
  2. Handle errors properly - Always use result<T, string> for operations that can fail
  3. Keep components focused - Each component should do one thing well
  4. Test thoroughly - Validate your component works before deploying
  5. Document your interfaces - Use WIT comments to explain your API

Common Patterns

Async Operations

export async function processData(input) {
    const result = await fetchExternalData(input);
    return result;
}

Type Conversions

// WIT types map to JavaScript as follows:
// s32, s64, u32, u64 -> Number
// f32, f64 -> Number
// string -> String
// bool -> Boolean
// list<T> -> Array
// record -> Object

Configuration

export const config = {
    timeout: 5000,
    retries: 3
};

Troubleshooting

Build Errors

  • Ensure Node.js version is 18 or later
  • Check that WIT interface matches your exports
  • Verify all dependencies are installed

Runtime Errors

  • Check WASI permission configuration
  • Validate input/output types match WIT interface
  • Review Wassette logs for details

Full Documentation

For complete details, including advanced topics, WASI interfaces, and more examples, see the JavaScript/TypeScript Development Guide.

Working Examples

See these complete working examples in the repository:

Next Steps