GoWM Navigation

GoWM - Enterprise Manager

v1.2.0 - 206/206 tests ✅

Cache Active

GoWM Documentation

JavaScript library for Go WebAssembly modules

GoWM ... (Go Wasm Manager) is a JavaScript library that simplifies loading and executing Go WASM modules in both Node.js and browser environments, with GitHub repository support and advanced memory management.

Main Features

  • Universal Loading - Load WASM from local files, URLs, or GitHub repositories
  • Cross-Platform - Works in Node.js and browser with automatic environment detection
  • TypeScript Support - Complete type definitions with IntelliSense support
  • GitHub Support - Direct loading from repositories with branch/tag support
  • Memory Management - Advanced buffer creation and cleanup for WASM interactions
  • Simple API - Clean interface for calling WASM functions and managing modules

Framework Integration - Coming in v1.1.1

React hooks and Vue.js composables will be available in GoWM v1.1.1. Current version (v1.1.0) provides core functionality only.

Installation

Add GoWM to your project

View on npm
bash
npm install gowm
bash
yarn add gowm
bash
pnpm add gowm

Quick Start

Basic usage examples with real function calls

javascript
import { loadFromGitHub, load, getStats } from 'gowm';

// Load from GitHub repository
const mathModule = await loadFromGitHub('benoitpetit/wasm-modules-repository', { 
  name: 'math',
  path: 'math-wasm',
  filename: 'main.wasm'
});

// Load from local file or URL
const localWasm = await load('./math.wasm', { name: 'local-math' });

// Function calls (synchronous)
const result = mathModule.call('add', 5, 3);
console.log('5 + 3 =', result); // 8

const multiply = mathModule.call('multiply', 6, 7);
console.log('6 × 7 =', multiply); // 42

// Advanced operations
const power = mathModule.call('power', 2, 8);
console.log('2^8 =', power); // 256

// Get available functions (via call method)
const availableFunctions = mathModule.call('getAvailableFunctions');
console.log('Available functions:', availableFunctions);

// Module statistics
const stats = mathModule.getStats();
console.log('Module info:', {
  name: stats.name,
  ready: stats.ready,
  functions: stats.functions.length,
  memoryUsage: stats.memoryUsage
});

// Global GoWM statistics
const globalStats = await getStats();
console.log('Total modules:', globalStats.modules?.length || 0);

GitHub Loading

Load WASM modules directly from repositories with intelligent file discovery

Basic GitHub Loading

javascript
import { loadFromGitHub } from 'gowm';

// Basic loading with automatic file discovery
const math = await loadFromGitHub('benoitpetit/wasm-modules-repository', {
  path: 'math-wasm',
  filename: 'main.wasm',
  name: 'math-basic'
});

// Enable silent mode and test functions
math.call('setSilentMode', true);
console.log('5 + 3 =', math.call('add', 5, 3));
console.log('Available functions:', math.call('getAvailableFunctions'));

Advanced GitHub Options

javascript
// Load with specific branch and advanced options
const crypto = await loadFromGitHub('benoitpetit/wasm-modules-repository', {
  path: 'crypto-wasm',
  filename: 'main.wasm',
  name: 'crypto-advanced',
  branch: 'master',        // Specify branch (default: auto-detected)
  skipCache: false,        // Enable caching (default: false)
  cacheTTL: 60 * 60 * 1000 // 1 hour cache TTL
});

// Load from specific tag or commit
const stable = await loadFromGitHub('owner/repo', {
  tag: 'v1.2.3',          // Use specific version (overrides branch)
  path: 'dist',
  filename: 'module.wasm',
  name: 'stable-version'
});

// Load from full GitHub URL
const image = await loadFromGitHub(
  'https://github.com/benoitpetit/wasm-modules-repository', 
  { 
    path: 'image-wasm',
    filename: 'main.wasm', 
    branch: 'master',
    name: 'image-processor'
  }
);

Automatic File Discovery

GoWM automatically searches for WASM files using intelligent patterns:

Search Priority

  1. 1. Specified path/filename
  2. 2. Module-specific paths
  3. 3. Root directory files
  4. 4. Common build folders
  5. 5. GitHub releases
  6. 6. Recursive search

Common Patterns

  • {name}/main.wasm
  • main.wasm, index.wasm
  • wasm/, dist/, build/
  • {repo-name}.wasm
  • • Release assets

Repository Format Support

javascript
// Supported repository formats:

// 1. Simple owner/repo
await loadFromGitHub('owner/repo');

// 2. With branch specification
await loadFromGitHub('owner/repo@main');

// 3. With path in repository
await loadFromGitHub('owner/repo/path/to/wasm');

// 4. With branch and path
await loadFromGitHub('owner/repo@branch/path/to/wasm');

// 5. Full GitHub URL
await loadFromGitHub('https://github.com/owner/repo');

// 6. Options override format parsing
await loadFromGitHub('owner/repo', {
  branch: 'develop',    // Overrides @branch in URL
  path: 'custom/path',  // Overrides path in URL
  tag: 'v2.0.0'        // Takes precedence over branch
});

Caching & Performance

javascript
// Advanced caching configuration
const module = await loadFromGitHub('owner/repo', {
  path: 'wasm',
  cacheTTL: 30 * 60 * 1000,     // 30 minutes cache
  refreshThreshold: 0.8,         // Refresh at 80% of TTL
  priority: 'high',              // Cache priority
  tags: ['production', 'v2'],    // Cache tags for invalidation
  dependencies: ['other-module'], // Cache dependencies
  backgroundRefresh: true,       // Enable background refresh
  preload: false                 // Don't preload immediately
});

// Multiple modules with shared caching
const [math, crypto] = await Promise.all([
  loadFromGitHub('repo/modules', { path: 'math-wasm', name: 'math' }),
  loadFromGitHub('repo/modules', { path: 'crypto-wasm', name: 'crypto' })
]);

Memory Management

Advanced buffer creation and cleanup for WASM interactions

Buffer Creation

Create buffers for efficient data transfer between JavaScript and WASM:

javascript
// Create buffer from typed array
const floatBuffer = wasm.createBuffer(new Float64Array([1.5, 2.7, 3.14]));
console.log('Float buffer:', floatBuffer.size, 'bytes');

// Create buffer from string
const textBuffer = wasm.createBuffer('Hello WASM World!');
console.log('Text buffer:', textBuffer.size, 'bytes');

// Create buffer from regular array
const intBuffer = wasm.createBuffer(new Uint8Array([1, 2, 3, 4, 5]));
console.log('Integer buffer:', intBuffer.size, 'bytes');

Buffer Usage in WASM Functions

Pass buffer pointers to WASM functions for processing:

javascript
// Process array data in WASM
const data = new Float64Array([1, 2, 3, 4, 5]);
const buffer = wasm.createBuffer(data);

// Pass buffer pointer and size to WASM function
const result = wasm.call('processArray', buffer.ptr, buffer.size);
console.log('Processing result:', result);

// Always clean up when done
buffer.free();

Memory Management Best Practices

Proper memory management prevents leaks and ensures optimal performance:

javascript
// Always use try-finally for cleanup
let buffer = null;
try {
  buffer = wasm.createBuffer(largeDataArray);
  const result = wasm.call('processLargeData', buffer.ptr, buffer.size);
  return result;
} finally {
  if (buffer) {
    buffer.free(); // Ensures cleanup even if errors occur
  }
}

// Check memory usage
const stats = wasm.getStats();
console.log('Allocated buffers:', stats.allocatedBuffers);
console.log('Memory usage:', stats.memoryUsage, 'bytes');

Memory Management Tips

  • • Always call buffer.free() when done with buffers
  • • Use try-finally blocks for guaranteed cleanup
  • • Monitor memory usage with wasm.getStats()
  • • Prefer smaller, frequent operations over large buffers

API Reference

Complete GoWM API documentation

Loading Functions

load(source, options)

Loads a WASM module from a local file or URL.

javascript
const module = await load('./math.wasm', { 
  name: 'math-module',
  goRuntimePath: './custom_wasm_exec.js'
});

loadFromGitHub(repo, options)

Loads a WASM module from a GitHub repository with automatic file discovery.

javascript
const module = await loadFromGitHub('user/repo', {
  name: 'github-module',
  branch: 'master',
  path: 'wasm',
  filename: 'module.wasm'
});

get(name)

Retrieves an already loaded module by name.

javascript
const module = get('my-module');
if (module) {
  const result = module.call('function', arg1, arg2);
}

unload(name)

Unloads a module and cleans up its resources.

javascript
const success = await unload('my-module');
console.log('Module unloaded:', success);

WasmBridge Methods

call(funcName, ...args)

Calls a WASM function synchronously.

javascript
const result = wasm.call('add', 5, 3);
const data = wasm.call('processData', buffer.ptr, buffer.size);

callAsync(funcName, ...args)

Calls a WASM function asynchronously.

javascript
const result = await wasm.callAsync('complexCalculation', data);
const processed = await wasm.callAsync('asyncOperation', input);

createBuffer(data)

Creates a buffer in WASM memory for data transfer.

javascript
const buffer = wasm.createBuffer(new Float64Array([1, 2, 3]));
console.log('Buffer:', buffer.size, 'bytes');
buffer.free(); // Always release memory

call("getAvailableFunctions")string[]

Returns a list of all available functions via WASM call method.

javascript
const functions = wasm.call('getAvailableFunctions');
console.log('Available functions:', functions);
// Example: ['add', 'multiply', 'setSilentMode', 'getAvailableFunctions']

call("getAvailableFunctions") → Check Functions

Check if a function exists by listing available functions.

javascript
const functions = wasm.call('getAvailableFunctions');
if (functions.includes('optionalFeature')) {
  const result = wasm.call('optionalFeature', data);
}

getStats()ModuleStats

Returns detailed statistics about the module.

javascript
const stats = wasm.getStats();
console.log('Module Statistics:', {
  name: stats.name,
  ready: stats.ready,
  functions: stats.functions,
  memoryUsage: stats.memoryUsage,
  allocatedBuffers: stats.allocatedBuffers
});

registerCallback(name, callback)void

Register a JavaScript callback that can be called from WASM (if supported).

javascript
wasm.registerCallback('logMessage', (message) => {
  console.log('From WASM:', message);
});

// WASM can now call logMessage('Hello from Go!')

cleanup()void

Manually cleans up module resources.

javascript
// Called automatically, but can be called manually
wasm.cleanup();

Management Functions

isLoaded(name)boolean | Promise<boolean>

Checks if a module is currently loaded.

javascript
// Synchronous check (browser)
if (isLoaded('my-module')) {
  console.log('Module is ready to use');
}

// Async check (Node.js)
if (await isLoaded('my-module')) {
  console.log('Module is ready to use');
}

listModules()Promise<string[]>

Returns array of loaded module names.

javascript
const modules = await listModules();
console.log('Loaded modules:', modules);

getStats()Promise<Record<string, ModuleStats>>

Returns statistics for all loaded modules.

javascript
const stats = await getStats();
Object.entries(stats).forEach(([name, stat]) => {
  console.log(`${name}: ${stat.memoryUsage} bytes`);
});

getTotalMemoryUsage()Promise<number>

Returns total memory usage of all loaded modules.

javascript
const totalMemory = await getTotalMemoryUsage();
console.log(`Total WASM memory: ${totalMemory} bytes`);

unloadAll()Promise<void>

Unloads all modules and cleans up resources.

javascript
await unloadAll(); // Clean slate

Core API Methods

loadFromGitHub(repo, options)Promise<WasmBridge>

Load a WASM module from GitHub repository with automatic file discovery.

javascript
const module = await loadFromGitHub('owner/repo', {
  branch: 'master',      // Git branch
  path: 'wasm-dir',      // Directory path
  filename: 'main.wasm', // Specific filename
  name: 'my-module'      // Module identifier
});

load(source, options)Promise<WasmBridge>

Universal loader with auto-detection for files, URLs, and GitHub repos.

javascript
// Auto-detection examples
const wasm1 = await load('owner/repo');              // GitHub
const wasm2 = await load('https://domain.com/mod.wasm'); // URL
const wasm3 = await load('./local.wasm');            // File

Framework Integration - Coming in v1.1.1

React hooks (useWasm) and Vue composables will be available in GoWM v1.1.1.

Load Options Reference

Basic Load Options

  • name - Module identifier (string)
  • goRuntimePath - Custom Go runtime path
  • preInit - Pre-initialize module (boolean, default: true)

GitHub Load Options

  • branch - Git branch (default: auto-detected)
  • tag - Git tag (overrides branch)
  • path - Path within repository
  • filename - Specific filename
  • cacheTTL - Cache TTL in milliseconds
  • skipCache - Disable caching (boolean)

Examples

Practical usage examples

Basic Node.js Example

javascript
const { load, loadFromGitHub } = require('gowm');

async function example() {
  try {
    // Load from GitHub
    const math = await loadFromGitHub('benoitpetit/wasm-modules-repository', { 
      name: 'math',
      path: 'math-wasm',
      branch: 'master'
    });
    
    // Load local
    const localWasm = await load('./math.wasm', { name: 'local-math' });
    
    // Function calls
    const result = math.call('add', 5, 3);
    console.log('5 + 3 =', result); // 8
    
    const asyncResult = await math.callAsync('multiply', 4, 7);
    console.log('4 * 7 =', asyncResult); // 28
    
    // Statistics
    const stats = math.getStats();
    console.log('Module info:', {
      name: stats.name,
      ready: stats.ready,
      functions: stats.functions.length,
      memoryUsage: stats.memoryUsage
    });
    
  } catch (error) {
    console.error('Error:', error.message);
  }
}

example();

Advanced Memory Management

javascript
import { loadFromGitHub } from 'gowm';

async function memoryExample() {
  const module = await loadFromGitHub('benoitpetit/wasm-modules-repository', {
    name: 'image-processor',
    path: 'image-wasm'
  });

  // Create different types of buffers
  const floatBuffer = module.createBuffer(new Float64Array([1, 2, 3, 4, 5]));
  const byteBuffer = module.createBuffer(new Uint8Array([65, 66, 67]));
  const stringBuffer = module.createBuffer('Hello, WASM!');

  try {
    // Use buffers in WASM calls
    const result = module.call('processArray', floatBuffer.ptr, floatBuffer.size);
    const processed = await module.callAsync('processBytes', byteBuffer.ptr, byteBuffer.size);
    
    // Monitor memory usage
    const stats = module.getStats();
    console.log('Memory usage:', stats.memoryUsage, 'bytes');
    console.log('Allocated buffers:', stats.allocatedBuffers);
    
  } finally {
    // Always clean up buffers
    floatBuffer.free();
    byteBuffer.free();
    stringBuffer.free();
  }
}

Advanced Caching Configuration

javascript
import { GoWM } from 'gowm';

// Initialize with custom cache config
const gowm = new GoWM({
  cache: {
    maxSize: 500 * 1024 * 1024, // 500MB max cache
    defaultTTL: 24 * 60 * 60 * 1000, // 24h default TTL
    refreshThreshold: 0.8 // Refresh at 80% of TTL
  }
});

// Load with cache configuration
const module = await gowm.loadFromGitHub('owner/repo', {
  cacheTTL: 30 * 60 * 1000, // 30 minutes
  priority: 'high',
  tags: ['production', 'v2']
});

// Get cache statistics
const stats = gowm.getCacheStats();
console.log({
  hitRate: `${(stats.hits / (stats.hits + stats.misses) * 100).toFixed(1)}%`,
  totalSize: `${(stats.totalSize / 1024 / 1024).toFixed(2)}MB`,
  entriesCount: stats.entriesCount
});

// Tag-based invalidation
gowm.invalidateByTag('api-v2'); // Remove all v2 API modules

Creating GoWM-Compatible WASM Modules

Build Go WASM modules that work seamlessly with GoWM

Basic Module Structure

A GoWM-compatible WASM module must follow specific patterns for function registration and initialization:

go
//go:build js && wasm

package main

import (
	"fmt"
	"syscall/js"
)

var silentMode = false

// setSilentMode enables/disables console output
func setSilentMode(this js.Value, args []js.Value) interface{} {
	if len(args) == 1 {
		silentMode = args[0].Bool()
	}
	return js.ValueOf(silentMode)
}

// Example function: add two numbers
func add(this js.Value, args []js.Value) interface{} {
	if len(args) != 2 {
		return js.ValueOf("Error: two arguments required for add")
	}

	a := args[0].Float()
	b := args[1].Float()
	result := a + b

	if !silentMode {
		fmt.Printf("Go WASM: %f + %f = %f\n", a, b, result)
	}
	return js.ValueOf(result)
}

// getAvailableFunctions returns list of available functions
func getAvailableFunctions(this js.Value, args []js.Value) interface{} {
	functions := []interface{}{
		"add", "setSilentMode", "getAvailableFunctions",
	}
	return js.ValueOf(functions)
}

func main() {
	fmt.Println("Go WASM Module initializing...")

	// Register functions on global scope
	js.Global().Set("add", js.FuncOf(add))
	js.Global().Set("setSilentMode", js.FuncOf(setSilentMode))
	js.Global().Set("getAvailableFunctions", js.FuncOf(getAvailableFunctions))

	// Signal readiness for GoWM (important!)
	js.Global().Set("__gowm_ready", js.ValueOf(true))

	fmt.Println("Go WASM Module ready!")

	// Keep the program alive
	select {}
}

Required Functions & Patterns

Essential Functions

  • getAvailableFunctions() - Returns array of function names
  • setSilentMode(bool) - Controls console output
  • __gowm_ready - Global flag indicating module is ready

Function Signature Pattern

go
func myFunction(this js.Value, args []js.Value) interface{} {
	// 1. Validate arguments
	if len(args) != expectedCount {
		return js.ValueOf("Error: description")
	}

	// 2. Extract and convert arguments
	param1 := args[0].Float()
	param2 := args[1].String()

	// 3. Perform operation
	result := doSomething(param1, param2)

	// 4. Optional logging (respect silentMode)
	if !silentMode {
		fmt.Printf("Operation result: %v\n", result)
	}

	// 5. Return js.Value
	return js.ValueOf(result)
}

Building Your Module

Using the Integrated WASM Manager (Recommended)

The wasm-projects repository includes a high-performance Go-based build system with parallel processing:

bash
# Clone the wasm-projects repository
git clone https://github.com/benoitpetit/wasm-projects.git
cd wasm-projects

# Setup the build manager
make setup

# Build all modules with parallel processing
./wasm-manager build

# Build specific module
./wasm-manager build math-wasm

# Build with custom worker count
./wasm-manager build --workers 8

# Build with optimizations (default)
./wasm-manager build --optimize

# Build without compression
./wasm-manager build --compress=false

# Validate module structure
./wasm-manager validate math-wasm

# Test module functionality
./wasm-manager test math-wasm

Manual Build Commands

bash
# Basic build command
GOOS=js GOARCH=wasm go build -o main.wasm main.go

# Optimized build (recommended)
GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o main.wasm main.go

# Using TinyGo for smaller binaries
tinygo build -o main.wasm -target wasm -no-debug main.go

# Build with wasm-opt optimization (if available)
wasm-opt -Oz main.wasm -o main.wasm

Advanced Features

go
// Error handling with structured responses
func processData(this js.Value, args []js.Value) interface{} {
	if len(args) != 1 {
		return js.ValueOf(map[string]interface{}{
			"error": "Invalid arguments",
			"code":  "INVALID_ARGS",
		})
	}

	data := args[0].String()
	result, err := complexOperation(data)
	
	if err != nil {
		return js.ValueOf(map[string]interface{}{
			"error": err.Error(),
			"code":  "PROCESSING_ERROR",
		})
	}

	return js.ValueOf(map[string]interface{}{
		"success": true,
		"data":    result,
		"size":    len(result),
	})
}

// Memory management helpers
func allocateBuffer(this js.Value, args []js.Value) interface{} {
	size := int(args[0].Float())
	// Allocate and return pointer for GoWM memory management
	return js.ValueOf(size) // Simplified example
}

// Callback registration for async operations
func registerCallback(this js.Value, args []js.Value) interface{} {
	callback := args[0]
	// Store callback for later use
	storedCallbacks = append(storedCallbacks, callback)
	return js.ValueOf("callback registered")
}

Testing Your Module

javascript
// test-module.js
import { load } from 'gowm';

async function testModule() {
  try {
    // Load your module
    const module = await load('./main.wasm', { name: 'my-module' });
    
    // Test basic functionality
    console.log('Available functions:', module.call('getAvailableFunctions'));
    
    // Test silent mode
    module.call('setSilentMode', true);
    
    // Test your functions
    const result = module.call('add', 5, 3);
    console.assert(result === 8, 'Add function should return 8');
    
    // Test error handling
    const error = module.call('add', 5); // Missing argument
    console.assert(typeof error === 'string' && error.includes('Error'), 'Should return error message');
    
    console.log('✅ All tests passed!');
    
  } catch (error) {
    console.error('❌ Test failed:', error);
  }
}

testModule();

WASM Manager Features

Parallel Processing

  • • Configurable worker pools
  • • Auto-detects CPU cores
  • • 5-10x faster builds
  • • Error isolation per module

Advanced Optimizations

  • • WASM-opt integration
  • • Gzip/Brotli compression
  • • Integrity hash generation
  • • Size analysis reporting

Validation & Testing

  • • Module structure validation
  • • Function compliance checks
  • • Metadata verification
  • • Automated testing

Build Management

  • • Module auto-discovery
  • • Clean build support
  • • Build artifact management
  • • Comprehensive reporting

Best Practices

  • • Use the integrated wasm-manager for production builds
  • • Always validate function arguments and return descriptive errors
  • • Implement getAvailableFunctions() and setSilentMode()
  • • Set __gowm_ready = true when module is initialized
  • • Use structured error responses with error codes
  • • Keep the main goroutine alive with select
  • • Test your module with GoWM before deployment
  • • Validate module structure with ./wasm-manager validate

Troubleshooting

Common issues and solutions

GitHub Repository Not Found

If loading from GitHub fails, check:

  • • Repository name and owner are correct
  • • Branch or tag exists
  • • Path to WASM file is correct
  • • Repository is public or you have permissions
javascript
try {
  const wasm = await loadFromGitHub('invalid/repo');
} catch (error) {
  if (error.code === 'REPO_NOT_FOUND') {
    console.log('Repository not found');
  } else if (error.code === 'WASM_FILE_NOT_FOUND') {
    console.log('WASM file not found in repository');
  }
}

WASM Memory Errors

For memory errors, try:

javascript
// Always free buffers manually
const buffer = wasm.createBuffer(data);
// ... use buffer
buffer.free(); // Important!

// Monitor memory usage
const stats = wasm.getStats();
console.log('Memory used:', stats.memoryUsage, 'bytes');

// Get total memory usage across all modules
const totalMemory = getTotalMemoryUsage();
console.log(`Total WASM memory: ${totalMemory} bytes`);

Function Not Found

Check that the function exists in the module:

javascript
// List available functions
const functions = wasm.getAvailableFunctions();
console.log('Available functions:', functions);

// Check if function exists
if (wasm.hasFunction('myFunction')) {
  const result = wasm.call('myFunction', args);
} else {
  console.error('Function myFunction not found');
}

Performance Issues

Best practices for optimal performance:

  • • Use module sharing across components
  • • Enable debug mode during development
  • • Configure cache TTL and priority based on usage
  • • Use async functions for heavy computations
  • • Monitor memory usage regularly