← Back to Lessons Lesson 15 of 28
Advanced dom

Wasm + Frontend Frameworks

The Pattern

Use Wasm for computation, your framework for UI:

┌─────────────────┐
│  React/Svelte   │  ← UI rendering, state, events
│  (JavaScript)   │
├─────────────────┤
│  Wasm Module    │  ← Heavy computation, data processing
│  (Rust)         │
└─────────────────┘

React Integration

// hooks/useWasm.ts
import { useState, useEffect } from 'react';

export function useWasm() {
  const [wasm, setWasm] = useState(null);

  useEffect(() => {
    async function load() {
      const module = await import('../pkg/my_wasm.js');
      await module.default();  // init
      setWasm(module);
    }
    load();
  }, []);

  return wasm;
}

// components/ImageEditor.tsx
function ImageEditor() {
  const wasm = useWasm();
  const [processing, setProcessing] = useState(false);

  async function applyBlur() {
    if (!wasm) return;
    setProcessing(true);

    const processor = new wasm.ImageProcessor(800, 600);
    const imageData = ctx.getImageData(0, 0, 800, 600);
    processor.blur(imageData.data, 3);
    ctx.putImageData(imageData, 0, 0);

    setProcessing(false);
  }

  return (
    <button onClick={applyBlur} disabled={!wasm || processing}>
      {processing ? 'Processing...' : 'Apply Blur'}
    </button>
  );
}

Svelte Integration

<!-- WasmProcessor.svelte -->
<script lang="ts">
  import { onMount } from 'svelte';

  let wasm: any = null;
  let ready = false;

  onMount(async () => {
    const module = await import('../pkg/my_wasm.js');
    await module.default();
    wasm = module;
    ready = true;
  });

  function processData() {
    if (!wasm) return;
    const result = wasm.process(inputData);
    // update UI with result
  }
</script>

{#if ready}
  <button on:click={processData}>Process</button>
{:else}
  <p>Loading Wasm...</p>
{/if}

Vue Integration

<!-- WasmComponent.vue -->
<script setup>
import { ref, onMounted } from 'vue';

const wasm = ref(null);
const ready = ref(false);

onMounted(async () => {
  const module = await import('../pkg/my_wasm.js');
  await module.default();
  wasm.value = module;
  ready.value = true;
});

function compute() {
  if (!wasm.value) return;
  const result = wasm.value.heavy_calculation(data);
}
</script>

<template>
  <button @click="compute" :disabled="!ready">Compute</button>
</template>

Vite Configuration

// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    exclude: ['my-wasm-app']  // Don't pre-bundle Wasm
  },
  server: {
    headers: {
      // Required for SharedArrayBuffer (optional)
      'Cross-Origin-Opener-Policy': 'same-origin',
      'Cross-Origin-Embedder-Policy': 'require-corp',
    }
  }
});

When to Use Wasm with a Framework

Use Wasm for Keep in JS/Framework
Image/video processing UI components, routing
Physics simulation State management (Redux, etc.)
Cryptography Form handling, validation
Data parsing (CSV, binary) DOM manipulation
Audio processing Event handling
Compression/decompression HTTP requests (unless perf-critical)

Rule of thumb: If it's CPU-bound and takes >10ms in JavaScript, move it to Wasm.

Try It

The starter code shows an ImageProcessor struct that works with any framework — it accepts raw pixel data and processes it in Rust.

Try It

Chapter Quiz

Pass all questions to complete this lesson