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
npm install gowm
yarn add gowm
pnpm add gowm
Quick Start
Basic usage examples with real function calls
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
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
// 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. Specified path/filename
- 2. Module-specific paths
- 3. Root directory files
- 4. Common build folders
- 5. GitHub releases
- 6. Recursive search
Common Patterns
- •
{name}/main.wasm
- •
main.wasm
,index.wasm
- •
wasm/
,dist/
,build/
- •
{repo-name}.wasm
- • Release assets
Repository Format Support
// 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
// 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:
// 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:
// 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:
// 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.
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.
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.
const module = get('my-module');
if (module) {
const result = module.call('function', arg1, arg2);
}
unload(name)
Unloads a module and cleans up its resources.
const success = await unload('my-module');
console.log('Module unloaded:', success);
WasmBridge Methods
call(funcName, ...args)
Calls a WASM function synchronously.
const result = wasm.call('add', 5, 3);
const data = wasm.call('processData', buffer.ptr, buffer.size);
callAsync(funcName, ...args)
Calls a WASM function asynchronously.
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.
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.
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.
const functions = wasm.call('getAvailableFunctions');
if (functions.includes('optionalFeature')) {
const result = wasm.call('optionalFeature', data);
}
getStats()
→ ModuleStats
Returns detailed statistics about the module.
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).
wasm.registerCallback('logMessage', (message) => {
console.log('From WASM:', message);
});
// WASM can now call logMessage('Hello from Go!')
cleanup()
→ void
Manually cleans up module resources.
// Called automatically, but can be called manually
wasm.cleanup();
Management Functions
isLoaded(name)
→ boolean | Promise<boolean>
Checks if a module is currently loaded.
// 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.
const modules = await listModules();
console.log('Loaded modules:', modules);
getStats()
→ Promise<Record<string, ModuleStats>>
Returns statistics for all loaded modules.
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.
const totalMemory = await getTotalMemoryUsage();
console.log(`Total WASM memory: ${totalMemory} bytes`);
unloadAll()
→ Promise<void>
Unloads all modules and cleans up resources.
await unloadAll(); // Clean slate
Core API Methods
loadFromGitHub(repo, options)
→ Promise<WasmBridge>
Load a WASM module from GitHub repository with automatic file discovery.
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.
// 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
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
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
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: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
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:
# 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
# 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
// 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
// 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()
andsetSilentMode()
- • 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
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:
// 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:
// 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