GitHub - AlaShiban/umo: A universal module compiler that compiles packages from popular language into portable WebAssembly modules that can be imported natively by other languages

6 min read Original article ↗

umo

Universal Modules — Write once, import anywhere. (A Claude Experiment)

umo demo

umo compiles packages from any language into universal WebAssembly modules that can be imported natively by any other language.

Python package  ──┐
                  │
Go module      ───┼──► WASM Component ──► Import from Node, Python, Go, Rust...
                  │
npm package    ───┘

Why umo?

Each programming language ecosystem has many useful libraries. Umo makes them available to every language.

Quick Start

Install a Python package for use in Node.js

# Install the humanize package as a universal module
umo pip-install humanize

# That's it. Now use it in JavaScript:
import { intcomma, naturalsize, ordinal } from './umo_modules/humanize/index.js';

console.log(intcomma(1000000));      // "1,000,000"
console.log(naturalsize(3000000));   // "3.0 MB"
console.log(ordinal(42));            // "42nd"

Full TypeScript support included — autocomplete, type checking, everything just works.

Use Python classes with persistent state

Python:

from redblacktree import rbtree

tree = rbtree()
tree.insert(5, 'five')
tree.insert(3, 'three')
tree.insert(7, 'seven')

print(tree.depth())           # 2
print(list(tree.inorder()))   # [(3, 'three'), (5, 'five'), (7, 'seven')]

Node.js (same types, same API):

import { Rbtree } from './umo_modules/redblacktree/index.js';

const tree = new Rbtree([]);
tree.insert(5, 'five');
tree.insert(3, 'three');
tree.insert(7, 'seven');

console.log(tree.depth());     // 2
console.log(tree.inorder());   // [[3,"three"],[5,"five"],[7,"seven"]]

Types map directly: Python int → JS number, Python list → JS array. State persists across calls.

Installation

Prerequisites

umo requires these tools (installed automatically or via your package manager):

Tool Purpose Install
Node.js 18+ Runtime nodejs.org
Python 3.11+ Python compilation python.org
componentize-py Python → WASM pip install componentize-py

Commands

umo pip-install <package>

Install a Python package as a universal module.

# Install latest version
umo pip-install humanize

# Install specific version
umo pip-install humanize@4.15.0

Output: Creates umo_modules/<package>/ with:

  • index.js — JavaScript bindings
  • index.d.ts — TypeScript declarations
  • bindings/ — WASM component and runtime

umo pip-list

List available curated packages.

How It Works

┌─────────────────┐
│  Python Package │
│   (humanize)    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Type Extraction │  Analyzes signatures, docstrings, type hints
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ WIT Generation  │  Creates WebAssembly Interface Types
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  componentize   │  Compiles Python + CPython to WASM
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ jco transpile   │  Generates JS bindings from WASM
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  umo_modules/   │  Ready to import!
│   humanize/     │
└─────────────────┘

Implementation: umo uses the WebAssembly Component Model to create portable, typed interfaces between languages. Functions calls cross the language boundary with native performance — no JSON serialization, no HTTP overhead.

Supported Languages

Source Languages (compile from)

Language Status Command
Python Stable umo pip-install <pkg>
TypeScript Planned umo npm-install <pkg>
Go Planned umo go-install <pkg>
Rust Planned umo cargo-install <pkg>

Target Languages (import into)

Language Status
JavaScript/TypeScript Stable
Python Planned
Go Planned
Rust Planned

Examples

Number Formatting

import {
  intcomma,
  intword,
  ordinal,
  apnumber,
  scientific,
  metric
} from './umo_modules/humanize/index.js';

intcomma(1234567);        // "1,234,567"
intword(1200000000);      // "1.2 billion"
ordinal(3);               // "3rd"
apnumber(5);              // "five"
scientific(0.00042, 2);   // "4.20 x 10⁻⁴"
metric(1500, "V", 3);     // "1.50 kV"

File Sizes

import { naturalsize } from './umo_modules/humanize/index.js';

naturalsize(300);          // "300 Bytes"
naturalsize(3000);         // "3.0 kB"
naturalsize(3000000);      // "3.0 MB"
naturalsize(3000000000);   // "3.0 GB"

Data Structures

import { Rbtree } from './umo_modules/redblacktree/index.js';

// Create a red-black tree (self-balancing BST)
const tree = new Rbtree([]);

// Stateful operations
tree.insert(10, 'ten');
tree.insert(5, 'five');
tree.insert(15, 'fifteen');

// Query - returns native JS types
console.log(tree.depth());     // 2 (number)
console.log(tree.inorder());   // [[5,"five"],[10,"ten"],[15,"fifteen"]]

Data Science with Pandas

import * as pd from './umo_modules/pandas/index.js';

// Create DataFrames
const df1 = await pd.DataFrame.create({ 'A': [1, 2], 'B': [3, 4] });
const df2 = await pd.DataFrame.create({ 'A': [5, 6], 'B': [7, 8] });

// Concatenate
const combined = await pd.concat([df1, df2]);

// Merge DataFrames
const left = await pd.DataFrame.create({ key: ['A', 'B'], val: [1, 2] });
const right = await pd.DataFrame.create({ key: ['A', 'C'], val: [3, 4] });
const merged = await pd.merge(left, right, 'inner', 'key');

// Check for missing values
console.log(await pd.isna(null));  // true

Type Safety

umo generates full TypeScript declarations from Python type hints:

// Auto-generated index.d.ts
export function intcomma(value: number, ndigits?: number): string;
export function naturalsize(value: number, binary?: boolean, gnu?: boolean): string;
export function ordinal(value: number): string;

export class Rbtree {
  constructor(initial: any[]);
  insert(key: number, value: string): void;
  remove(key: number): void;
  depth(): number;
  inorder(): Array<[number, string]>;
}

Your editor provides autocomplete, parameter hints, and type checking — just like native packages.

Validated Packages

umo has been tested with 30+ Python packages across different categories. Here's a sample:

Package Category Description
pandas Data Science DataFrames, data analysis (via Pyodide)
networkx Data Science Graph/network analysis (via Pyodide)
sqlalchemy Database SQL toolkit and ORM
flask Web Web microframework
jinja2 Templating Template engine
beautifulsoup4 Parsing HTML/XML parsing
humanize Formatting Human-readable numbers, dates, sizes
click CLI Command-line interface framework
arrow Date/Time Date and time handling
redblacktree Data Structures Self-balancing binary search tree

View full list of validated packages — includes 30+ packages across web, data, CLI, utilities, and more.

Note: We validate that packages compile and run with basic tests. We don't maintain full test suite translations from the original Python packages.

Limitations

Current Limitations

  • Python stdlib: Some stdlib modules aren't available in WASM (e.g., _ssl, mmap)
  • Native extensions: Some packages with C/Rust extensions require Pyodide runtime (pandas, networkx, numpy work; requests, pydantic don't)
  • File I/O: Limited filesystem access in WASM sandbox
  • Networking: No direct network access from WASM

Coming Later

  • Go module compilation
  • TypeScript/npm package compilation
  • Import WASM modules into Python
  • Import WASM modules into Go
  • Browser support (run Python packages client-side)
  • Package registry for pre-compiled modules

Architecture

umo/
├── src/
│   ├── cli.ts                 # CLI entry point
│   ├── pip/
│   │   ├── package-resolver.ts    # pip package resolution
│   │   ├── type-extractor.ts      # Python type analysis
│   │   ├── wit-generator.ts       # WIT interface generation
│   │   ├── wasm-compiler.ts       # componentize-py integration
│   │   ├── js-generator.ts        # JavaScript binding generation
│   │   └── dts-generator.ts       # TypeScript declaration generation
│   ├── compiler/              # WASM compilation utilities
│   └── utils/                 # Shared utilities
├── umo_modules/               # Compiled universal modules
└── tests/                     # Test suite

Development

# Clone and install
git clone https://github.com/AlaShiban/umo
cd umo
npm install

# Build
npm run build

# Run tests
npm test

# Development mode
npm run dev

FAQ

Q: How big are the compiled modules? A: Python modules include the CPython runtime (~30-50MB). This is cached and shared across modules.

Q: Is it fast? A: Function calls have near-native overhead. The WASM boundary is much faster than HTTP/IPC. First load has a startup cost; subsequent calls are fast.

Q: What about async/await? A: Async functions are supported in the Python source. The JS bindings are synchronous for now.

License

MIT

Credits

Built on the incredible work of:


umo — Universal Modules for a polyglot world