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
- Less aggressive wasm-opt settings: Tried
-O2
instead of-Os
, but still failed - Disabling specific wasm-opt passes: Complex and unreliable
- Different crypto libraries: Would require significant changes to circle_client_ws
- WASM-specific crypto implementations: Would add complexity and maintenance burden
Benefits of This Solution
- Backward Compatibility: Existing native applications continue to work unchanged
- WASM Compatibility: Browser applications can use the framework without wasm-opt issues
- Clear Separation: Feature flags make the trade-offs explicit
- Maintainable: Simple conditional compilation without code duplication
- Future-Proof: Can easily add more features or modes as needed
Testing
The solution was verified by:
- Building the website example without framework dependency ✅
- Adding framework dependency without crypto features ✅
- Building with wasm-opt aggressive optimizations ✅
- 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"] }