Tristan Cartledge 205a80e421 feat: optimize QuickJS implementation for minimal size
- Remove hardcoded JavaScript code and default transformation
- Make JavaScript code required as command-line argument
- Streamline dependencies (remove wasm-bindgen, serde, web-sys)
- Convert from library to binary target for cleaner WASI execution
- Update binary size: 718KB raw, 285KB gzipped
- Maintain full Wasmer compatibility and flexibility
- Update all documentation with correct sizes
- Uses QuickJS-NG (Next Generation) JavaScript engine
2025-08-18 15:18:43 +10:00

JavaScript to WebAssembly Compilation Comparison

A comprehensive analysis and comparison of different approaches to compile JavaScript to WebAssembly, with a focus on size optimization and runtime compatibility.

🎯 Overview

This repository explores 5 different JavaScript-to-WASM compilation approaches:

  1. QuickJS (Rust) - 285KB gzipped Recommended for Wasmer
  2. Javy Static - 519KB gzipped Wasmer Compatible
  3. Javy Dynamic - 488KB + 2KB per module (Node.js only)
  4. Porffor - 75KB gzipped (Node.js only)
  5. Go/TinyGo + Goja - 92KB-3.7MB gzipped (Browser/Node.js only)

🏆 Key Results

Wasmer Runtime Compatibility

  • QuickJS: Perfect compatibility, 285KB gzipped
  • Javy Static: Perfect compatibility, 519KB gzipped
  • All others: Require Node.js runtime or have compatibility issues

Size Comparison (Gzipped)

Implementation Size Runtime Wasmer Best For
QuickJS 285KB WASI Production Wasmer
Javy Static 519KB WASI Full JS Compatibility
Porffor 75KB Standard Size-critical Node.js
TinyGo Basic 92KB Go Runtime Browser applications
Javy Dynamic 490KB WASI Node.js multi-module
Goja 3.7MB Go Runtime Full JS engine in Go

🚀 Quick Start

Prerequisites

  • Go 1.21+
  • Rust with wasm32-wasip1 target
  • Node.js 18+
  • Javy
  • Porffor
  • Wasmer (optional, for testing)

Build All Implementations

# Install dependencies
make install-deps

# Build all implementations
make build-all

# Test all implementations
make test-all

# Test Wasmer compatibility
make test-wasmer

Build Individual Implementations

cd implementations/quickjs
cargo build --release --target wasm32-wasip1

Javy Static

cd implementations/javy
javy build -o transform.wasm transform.js

Porffor

cd implementations/porffor
porffor transform.js -o transform.wasm

📊 Detailed Analysis

Performance Characteristics

QuickJS

  • Cold start: ~5ms
  • Execution: ~1ms per operation
  • Memory: ~2MB baseline
  • Scaling: Excellent for multiple operations

Javy Static

  • Cold start: ~8ms
  • Execution: ~1ms per operation
  • Memory: ~3MB baseline
  • Scaling: Good for multiple operations

Runtime Compatibility

WASI Compatible (Wasmer Ready)

  • QuickJS: Perfect compatibility, uses standard WASI interfaces
  • Javy Static: Perfect compatibility, self-contained

Node.js/Browser Only

  • Porffor: Uses legacy WASM exceptions
  • Go/TinyGo: Requires wasm_exec.js runtime
  • Javy Dynamic: Needs dynamic linking support

🔧 Implementation Details

QuickJS Implementation

  • Language: Rust
  • Engine: QuickJS JavaScript engine
  • Target: wasm32-wasip1
  • Features: Full ECMAScript support, WASI I/O

Javy Implementation

  • Language: JavaScript
  • Engine: QuickJS (via Javy)
  • Target: WASI
  • Features: Bytecode Alliance quality, multiple build modes

Porffor Implementation

  • Language: JavaScript
  • Engine: AOT compiled
  • Target: Standard WASM
  • Features: Smallest size, compile-time optimization

📁 Repository Structure

├── implementations/
│   ├── quickjs/          # Rust + QuickJS (RECOMMENDED)
│   ├── javy/             # Javy static/dynamic builds
│   ├── porffor/          # Porffor AOT compilation
│   ├── goja/             # Go + Goja JavaScript engine
│   └── tinygo/           # TinyGo basic implementation
├── docs/
│   ├── BINARY_SIZES.md           # Detailed size analysis
│   ├── WASMER_COMPATIBILITY.md   # Runtime compatibility guide
│   ├── JAVY_WASMER_ANALYSIS.md   # Javy-specific analysis
│   └── FINAL_WASMER_SUMMARY.md   # Executive summary
├── tests/                # Test suites and benchmarks
├── Makefile             # Build automation
└── README.md           # This file

🧪 Testing

Unit Tests

npm test

Wasmer Compatibility Tests

make test-wasmer

Size Analysis

make measure-sizes

Performance Benchmarks

make benchmark

📖 Documentation

🔬 Research Findings

Wasmer v6.1.0-rc.2 Dynamic Linking

  • Introduces dynamic linking for WASIX/C++ libraries
  • Does NOT support WASM module import resolution
  • Javy dynamic builds still require Node.js runtime

Size Optimization Techniques

  • wasm-opt: 15-20% size reduction
  • Compression: 60-70% reduction with gzip
  • Dead code elimination: Significant impact on Go builds

Runtime Performance

  • WASI overhead: Minimal (~1ms)
  • JavaScript engine startup: 5-10ms
  • Execution performance: Comparable to native JavaScript

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add your implementation in implementations/
  4. Update documentation and tests
  5. Submit a pull request

📄 License

MIT License - see LICENSE for details.

🙏 Acknowledgments


For production Wasmer deployment, use QuickJS (285KB) for optimal size or Javy Static (519KB) for maximum JavaScript compatibility.

Description
No description provided
Readme MIT 1.6 MiB
Languages
JavaScript 47.8%
Shell 15.9%
Python 11.9%
TypeScript 11.1%
Go 6.8%
Other 6.5%