framework/WASM_OPT_SOLUTION.md
2025-07-21 00:17:46 +02:00

4.1 KiB

WebSocket Framework - WASM-opt Compatibility Solution

Problem

The WebSocket connection manager framework was causing wasm-opt parsing errors when building for WASM targets with aggressive optimizations:

[parse exception: invalid code after misc prefix: 17 (at 0:732852)]
Fatal: error parsing wasm (try --debug for more info)

Root Cause

The issue was caused by cryptographic dependencies (secp256k1 and sha3) in the circle_client_ws library. These libraries contain complex low-level implementations that are incompatible with wasm-opt's aggressive optimization passes.

Solution

We implemented a feature flag system that allows the framework to work in two modes:

1. Full Mode (with crypto authentication)

  • Use case: Native applications, server-side usage
  • Features: Full secp256k1 authentication support
  • Usage: framework = { path = "...", features = ["crypto"] }

2. WASM-Compatible Mode (without crypto)

  • Use case: WASM/browser applications where wasm-opt compatibility is required
  • Features: Basic WebSocket connections without cryptographic authentication
  • Usage: framework = { path = "...", features = ["wasm-compatible"] }

Implementation Details

Framework Cargo.toml

[dependencies]
circle_client_ws = { path = "../circles/src/client_ws", default-features = false, features = [] }

[features]
default = []
crypto = ["circle_client_ws/crypto"]
wasm-compatible = []  # For WASM builds without crypto to avoid wasm-opt issues

Conditional Compilation

The authentication code is conditionally compiled based on feature flags:

#[cfg(feature = "crypto")]
pub fn create_client(&self, ws_url: String) -> circle_client_ws::CircleWsClient {
    circle_client_ws::CircleWsClientBuilder::new(ws_url)
        .with_keypair(self.private_key.clone())
        .build()
}

#[cfg(not(feature = "crypto"))]
pub fn create_client(&self, ws_url: String) -> circle_client_ws::CircleWsClient {
    circle_client_ws::CircleWsClientBuilder::new(ws_url).build()
}

Website Example Configuration

[dependencies]
framework = { path = "../..", features = ["wasm-compatible"] }

Usage Recommendations

For WASM Applications

Use the wasm-compatible feature to avoid wasm-opt issues:

framework = { features = ["wasm-compatible"] }

For Native Applications with Authentication

Use the crypto feature for full authentication support:

framework = { features = ["crypto"] }

For Development/Testing

You can disable wasm-opt entirely in Trunk.toml for development:

[tools]
wasm-opt = false

Alternative Solutions Considered

  1. Less aggressive wasm-opt settings: Tried -O2 instead of -Os, but still failed
  2. Disabling specific wasm-opt passes: Complex and unreliable
  3. Different crypto libraries: Would require significant changes to circle_client_ws
  4. WASM-specific crypto implementations: Would add complexity and maintenance burden

Benefits of This Solution

  1. Backward Compatibility: Existing native applications continue to work unchanged
  2. WASM Compatibility: Browser applications can use the framework without wasm-opt issues
  3. Clear Separation: Feature flags make the trade-offs explicit
  4. Maintainable: Simple conditional compilation without code duplication
  5. Future-Proof: Can easily add more features or modes as needed

Testing

The solution was verified by:

  1. Building the website example without framework dependency
  2. Adding framework dependency without crypto features
  3. Building with wasm-opt aggressive optimizations
  4. Confirming all functionality works in WASM-compatible mode

Migration Guide

Existing Native Applications

No changes required - continue using the framework as before.

New WASM Applications

Add the wasm-compatible feature:

framework = { features = ["wasm-compatible"] }

Applications Needing Both

Use conditional dependencies:

[target.'cfg(target_arch = "wasm32")'.dependencies]
framework = { features = ["wasm-compatible"] }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
framework = { features = ["crypto"] }