WebAssembly modularity and dynamic loading are key features for building large-scale applications:
1. WebAssembly Module Structure
- Module: Basic compilation unit of WebAssembly
- Imports: Import functions, memory, tables, etc. from external environment
- Exports: Export functions, memory, tables, etc. to external environment
- Instance: Runtime instance of a module
javascript// Module structure example const module = await WebAssembly.compile(wasmBinary); const instance = await WebAssembly.instantiate(module, importObject);
2. Dynamic Loading of WebAssembly
javascript// Method 1: Using fetch and WebAssembly.instantiate async function loadWasm(url) { const response = await fetch(url); const buffer = await response.arrayBuffer(); const module = await WebAssembly.compile(buffer); const instance = await WebAssembly.instantiate(module, importObject); return instance; } // Method 2: Using WebAssembly.instantiateStreaming (recommended) async function loadWasmStreaming(url) { const { instance } = await WebAssembly.instantiateStreaming( fetch(url), importObject ); return instance; } // Method 3: Using WebAssembly.instantiate (compile and instantiate in one step) async function loadWasmDirect(url) { const response = await fetch(url); const buffer = await response.arrayBuffer(); const { instance } = await WebAssembly.instantiate(buffer, importObject); return instance; }
3. Modular Design
javascript// Main module import { utils } from './utils.wasm'; import { processing } from './processing.wasm'; import { rendering } from './rendering.wasm'; async function initApp() { const utilsModule = await loadWasm('utils.wasm'); const processingModule = await loadWasm('processing.wasm'); const renderingModule = await loadWasm('rendering.wasm'); // Combine multiple modules const data = utilsModule.exports.parseData(input); const processed = processingModule.exports.process(data); renderingModule.exports.render(processed); }
4. On-demand Loading
javascript// Lazy load WebAssembly modules let wasmModule = null; async function getWasmModule() { if (!wasmModule) { wasmModule = await WebAssembly.instantiateStreaming( fetch('heavy-computation.wasm'), importObject ); } return wasmModule; } // Load only when needed async function performHeavyComputation(data) { const module = await getWasmModule(); return module.exports.compute(data); }
5. Parallel Loading of Multiple Modules
javascript// Load multiple WebAssembly modules in parallel async function loadMultipleModules() { const [utils, processing, rendering] = await Promise.all([ WebAssembly.instantiateStreaming(fetch('utils.wasm'), importObject), WebAssembly.instantiateStreaming(fetch('processing.wasm'), importObject), WebAssembly.instantiateStreaming(fetch('rendering.wasm'), importObject) ]); return { utils, processing, rendering }; }
6. Module Caching
javascript// Cache WebAssembly modules using Service Worker self.addEventListener('install', (event) => { event.waitUntil( caches.open('wasm-cache').then((cache) => { return cache.addAll([ 'module1.wasm', 'module2.wasm', 'module3.wasm' ]); }) ); }); // Load from cache async function loadFromCache(url) { const cache = await caches.open('wasm-cache'); const response = await cache.match(url); if (response) { const buffer = await response.arrayBuffer(); return WebAssembly.instantiate(buffer, importObject); } // Cache miss, load from network return WebAssembly.instantiateStreaming(fetch(url), importObject); }
7. Module Version Management
javascript// Versioned WebAssembly modules const WasmVersions = { v1: 'module-v1.wasm', v2: 'module-v2.wasm', v3: 'module-v3.wasm' }; async function loadModule(version) { const url = WasmVersions[version] || WasmVersions.v1; return WebAssembly.instantiateStreaming(fetch(url), importObject); } // A/B testing async function loadModuleForABTest() { const version = Math.random() > 0.5 ? 'v2' : 'v1'; return loadModule(version); }
8. Inter-module Communication
javascript// Inter-module communication using shared memory const sharedMemory = new WebAssembly.Memory({ initial: 10, maximum: 100, shared: true }); const importObject1 = { env: { memory: sharedMemory } }; const importObject2 = { env: { memory: sharedMemory } }; // Two modules share the same memory const module1 = await WebAssembly.instantiateStreaming( fetch('module1.wasm'), importObject1 ); const module2 = await WebAssembly.instantiateStreaming( fetch('module2.wasm'), importObject2 );
9. Error Handling and Fallback
javascriptasync function loadWasmWithFallback(url, fallbackUrl) { try { return await WebAssembly.instantiateStreaming(fetch(url), importObject); } catch (error) { console.warn(`Failed to load ${url}, trying fallback`, error); return await WebAssembly.instantiateStreaming(fetch(fallbackUrl), importObject); } } // Feature detection async function loadWasmWithFeatureDetection(url) { if (!WebAssembly.instantiateStreaming) { console.warn('Streaming compilation not supported, using fallback'); const response = await fetch(url); const buffer = await response.arrayBuffer(); return WebAssembly.instantiate(buffer, importObject); } return WebAssembly.instantiateStreaming(fetch(url), importObject); }
10. Performance Optimization
- Use
instantiateStreamingfor streaming compilation - Load multiple independent modules in parallel
- Implement module caching to reduce network requests
- On-demand loading to avoid unnecessary resource consumption
- Use shared memory to reduce data copying
11. Best Practices
- Reasonably partition module boundaries for better reusability
- Use version management to control module updates
- Implement error handling and fallback strategies
- Leverage caching to improve loading performance
- Monitor module loading and execution performance