WebAssembly has mature toolchains beyond Rust. Go compiles to WASM with minimal changes and brings garbage collection. AssemblyScript lets TypeScript developers write WASM without learning a new language. The WASM component model enables language-agnostic module composition. Claude Code generates the build configs, JavaScript bindings, and integration patterns for each approach.
Go to WebAssembly
Compile our Go CSV parsing and validation library to WebAssembly.
It should expose: parseCSV(csvString) and validateRow(row, schema).
Run in the browser and in Node.js.
// lib/csv_processor.go
//go:build js,wasm
package main
import (
"encoding/csv"
"encoding/json"
"strings"
"syscall/js"
)
func parseCSV(this js.Value, args []js.Value) any {
if len(args) < 1 {
return js.ValueOf(map[string]any{"error": "csvString required"})
}
csvString := args[0].String()
reader := csv.NewReader(strings.NewReader(csvString))
records, err := reader.ReadAll()
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
}
if len(records) == 0 {
return js.ValueOf(map[string]any{"headers": []any{}, "rows": []any{}})
}
headers := make([]any, len(records[0]))
for i, h := range records[0] {
headers[i] = h
}
rows := make([]any, len(records)-1)
for i, record := range records[1:] {
row := make(map[string]any)
for j, value := range record {
if j < len(records[0]) {
row[records[0][j]] = value
}
}
rows[i] = row
}
return js.ValueOf(map[string]any{
"headers": js.ValueOf(headers),
"rows": js.ValueOf(rows),
})
}
func validateRow(this js.Value, args []js.Value) any {
if len(args) < 2 {
return js.ValueOf(map[string]any{"valid": false, "errors": []any{"row and schema required"}})
}
// Parse JSON arguments
rowJSON := args[0].String()
schemaJSON := args[1].String()
var row map[string]string
var schema map[string]string // field → type: "string", "number", "email", "required"
if err := json.Unmarshal([]byte(rowJSON), &row); err != nil {
return js.ValueOf(map[string]any{"valid": false, "errors": []any{err.Error()}})
}
if err := json.Unmarshal([]byte(schemaJSON), &schema); err != nil {
return js.ValueOf(map[string]any{"valid": false, "errors": []any{err.Error()}})
}
var errors []any
for field, rules := range schema {
value, exists := row[field]
if rules == "required" && (!exists || value == "") {
errors = append(errors, field+" is required")
}
}
valid := len(errors) == 0
if valid {
return js.ValueOf(map[string]any{"valid": true, "errors": []any{}})
}
return js.ValueOf(map[string]any{"valid": false, "errors": errors})
}
func main() {
// Register functions on the global JS object
js.Global().Set("goParseCSV", js.FuncOf(parseCSV))
js.Global().Set("goValidateRow", js.FuncOf(validateRow))
// Keep the WASM module alive
<-make(chan struct{})
}
# Build: requires GOOS=js GOARCH=wasm
GOOS=js GOARCH=wasm go build -o dist/csv_processor.wasm ./lib
# Copy the Go WASM support file
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" dist/
// src/wasm/go-csv.ts
let wasmReady: Promise<void>;
export function initGoWASM(): Promise<void> {
if (wasmReady) return wasmReady;
wasmReady = new Promise<void>(async (resolve) => {
// @ts-ignore — wasm_exec.js adds Go to global
const go = new Go();
const result = await WebAssembly.instantiateStreaming(
fetch('/wasm/csv_processor.wasm'),
go.importObject,
);
go.run(result.instance);
resolve();
});
return wasmReady;
}
export async function parseCSV(csvString: string) {
await initGoWASM();
// @ts-ignore — registered by Go main()
return globalThis.goParseCSV(csvString);
}
AssemblyScript
Write an AssemblyScript module for fast array statistics:
min, max, mean, median, standard deviation.
Operates on Float64Arrays for performance.
// assembly/stats.ts
// AssemblyScript — TypeScript syntax, compiles to WASM
export function min(arr: Float64Array): f64 {
if (arr.length === 0) return f64.NaN;
let result = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] < result) result = arr[i];
}
return result;
}
export function max(arr: Float64Array): f64 {
if (arr.length === 0) return f64.NaN;
let result = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > result) result = arr[i];
}
return result;
}
export function mean(arr: Float64Array): f64 {
if (arr.length === 0) return f64.NaN;
let sum: f64 = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum / f64(arr.length);
}
export function stddev(arr: Float64Array): f64 {
if (arr.length < 2) return f64.NaN;
const m = mean(arr);
let variance: f64 = 0;
for (let i = 0; i < arr.length; i++) {
const diff = arr[i] - m;
variance += diff * diff;
}
return Math.sqrt(variance / f64(arr.length - 1));
}
export function median(arr: Float64Array): f64 {
if (arr.length === 0) return f64.NaN;
// Sort a copy
const sorted = new Float64Array(arr.length);
for (let i = 0; i < arr.length; i++) sorted[i] = arr[i];
// Insertion sort (fast for small arrays; for large use quickselect)
for (let i = 1; i < sorted.length; i++) {
const key = sorted[i];
let j = i - 1;
while (j >= 0 && sorted[j] > key) {
sorted[j + 1] = sorted[j];
j--;
}
sorted[j + 1] = key;
}
const mid = sorted.length >> 1;
if (sorted.length % 2 === 0) {
return (sorted[mid - 1] + sorted[mid]) / 2.0;
}
return sorted[mid];
}
// asconfig.json
{
"targets": {
"release": {
"outFile": "dist/stats.wasm",
"optimize": true,
"noAssert": true,
"treeShaking": true
},
"debug": {
"outFile": "dist/stats.debug.wasm",
"debug": true
}
}
}
// src/wasm/stats.ts — TypeScript wrapper with proper typing
import { instantiate } from '../assembly/stats.js'; // Generated by asc
let wasmModule: Awaited<ReturnType<typeof instantiate>> | null = null;
async function getModule() {
if (!wasmModule) {
const response = await fetch('/wasm/stats.wasm');
const buffer = await response.arrayBuffer();
wasmModule = await instantiate(buffer, {});
}
return wasmModule;
}
export async function computeStats(data: number[]) {
const mod = await getModule();
const arr = new Float64Array(data);
return {
min: mod.min(arr),
max: mod.max(arr),
mean: mod.mean(arr),
median: mod.median(arr),
stddev: mod.stddev(arr),
};
}
WASM with SharedArrayBuffer and Workers
Process a large dataset with WASM in a Web Worker.
Share memory between the main thread and worker for zero-copy transfer.
// worker.ts
import initWasm, { process_chunk } from './wasm/processor.js';
let wasmInitialized = false;
self.onmessage = async (event: MessageEvent) => {
if (!wasmInitialized) {
await initWasm(); // Initialize WASM in the worker
wasmInitialized = true;
}
const { buffer, offset, length, taskId } = event.data;
// SharedArrayBuffer — zero-copy, shared with main thread
const shared = new Float32Array(buffer, offset, length);
const result = process_chunk(shared); // WASM call on worker thread
self.postMessage({ taskId, result });
};
// main thread
const worker = new Worker(new URL('./worker.ts', import.meta.url));
// Allocate shared memory — must serve with COOP/COEP headers
const sharedBuffer = new SharedArrayBuffer(largeDataset.length * 4);
const sharedView = new Float32Array(sharedBuffer);
sharedView.set(largeDataset); // Single copy into shared memory
worker.postMessage({ buffer: sharedBuffer, offset: 0, length: largeDataset.length, taskId: 1 });
// WASM processes in worker without copying the data again
WASM in Node.js
// server/wasm-processor.ts — use WASM in Node.js for CPU-intensive operations
import { readFileSync } from 'fs';
import { join } from 'path';
let wasmInstance: WebAssembly.Instance | null = null;
export async function initServerWasm() {
const wasmBuffer = readFileSync(join(__dirname, '../wasm/processor.wasm'));
const { instance } = await WebAssembly.instantiate(wasmBuffer, {
env: {
abort: (message: number, fileName: number, line: number, column: number) => {
throw new Error(`WASM abort at ${line}:${column}`);
},
},
});
wasmInstance = instance;
}
export function processDataSync(inputLength: number): number {
if (!wasmInstance) throw new Error('WASM not initialized');
return (wasmInstance.exports.process as Function)(inputLength);
}
For the original Rust-based WASM guide covering wasm-pack and wasm-bindgen, see the WebAssembly guide. For performance profiling to determine when WASM is worth the complexity, see the performance optimization guide. The Claude Skills 360 bundle includes WASM skill sets for multi-language compilation, worker integration, and production deployment. Start with the free tier to try WASM project scaffolding.