Architecture overview
The WASM rewriter is a Cargo workspace with multiple components:Key dependencies
Scramjet uses OXC, a blazingly fast JavaScript parser written in Rust, achieving performance comparable to native compilers.
WASM module structure
Initialization
The WASM module is loaded and initialized insrc/shared/rewriters/wasm.ts:
Service worker WASM loading
In service workers, WASM is fetched dynamically:Rewriter class
The WASMRewriter class exposes a JavaScript-friendly API:
TypeScript bindings
The Rust code generates TypeScript definitions:Rewriter configuration
TheRewriter constructor accepts a configuration object:
Shared functions
The rewriter calls back into JavaScript for certain operations:- URL rewriting:
rewriteUrl(url, meta) - CSS rewriting:
rewriteCss(css, meta)(for<style>tags) - JS rewriting:
rewriteJs(js, url, meta)(for nested scripts) - HTML injection:
getHtmlInjectCode(cookieStore, foundHead)
Why callbacks instead of pure Rust?
Why callbacks instead of pure Rust?
While implementing everything in Rust would be faster, JavaScript callbacks provide:
- Flexibility: Configuration (codec, flags) can be changed without recompiling WASM
- Code sharing: URL/CSS rewriting logic is shared between client and worker contexts
- Smaller binary: Avoiding duplicate implementations reduces WASM size
- Maintainability: Complex logic (HTML parsing) stays in TypeScript where it’s easier to debug
AST transformation
The Rust rewriter performs AST-level transformations using OXC:Visitor pattern
The visitor walks the AST and collects transformations:Building the WASM module
Scramjet includes a build script for the WASM module:Build configuration
For production builds, Scramjet uses aggressive optimizations:The production WASM binary is approximately 500KB gzipped, which is loaded once and cached by the browser.
Sourcemap generation
The rewriter generates sourcemaps for debugging:- Accurate stack traces in DevTools
- Breakpoint debugging in original code
- Proper error line numbers
Error handling
Parse errors
The rewriter collects parse errors without failing:Panic recovery
If OXC panics, the rewriter catches it:Performance optimizations
Rewriter pooling
Scramjet maintains a pool of rewriter instances:Usage
Always release the rewriter back to the pool using the
release() function to avoid memory leaks and rewriter exhaustion.Testing the rewriter
Scramjet includes a native test runner:- Debugging Rust code
- Running benchmarks
- Integration tests