Skip to content

RuvLLM WASM Dashboard Integration - Issues and Fixes #72

@ruvnet

Description

@ruvnet

Summary

This issue documents the problems encountered during RuvLLM WASM integration with the rvlite dashboard and their solutions.

Problems Identified

1. Vite Cannot Import JS Files from /public Folder

Error:

Cannot import non-asset file /pkg/ruvllm_wasm.js which is inside /public.
JS/CSS files inside /public are copied as-is on build and can only be referenced
via <script src> or <link href> in html.

Root Cause: Vite's security model prevents dynamic imports of JavaScript files from the /public folder. WASM JS glue code was being served from /public/pkg/ which Vite blocks.

Solution: Moved WASM files from public/pkg/ to src/wasm/ and updated the import strategy:

// Before (broken)
const wasmModule = await import('/pkg/ruvllm_wasm.js');

// After (working)
const wasmModule = await import('../wasm/ruvllm_wasm.js');
const wasmBinaryUrl = new URL('../wasm/ruvllm_wasm_bg.wasm', import.meta.url).href;

2. TypeScript Type Mismatch with Generated WASM Types

Error:

TS2352: Conversion of type 'typeof import(...ruvllm_wasm)' to type 'RuvLLMWasmModule' may be a mistake

Root Cause: Manual interface definitions in useRuvLLM.ts didn't match the types generated by wasm-bindgen in ruvllm_wasm.d.ts.

Solution: Refactored to import types directly from the generated .d.ts file and use proper type assertions with as unknown as RuvLLMWasmModule.

3. ReactNode Type Error with Unknown State

Error:

TS2322: Type 'unknown' is not assignable to type 'ReactNode'.

Root Cause: benchmarkResult state was typed as unknown, and TypeScript's strict mode prevented its use in JSX.

Solution: Changed type from unknown to Record<string, unknown> | null:

// Before
const [benchmarkResult, setBenchmarkResult] = useState<unknown>(null);

// After
const [benchmarkResult, setBenchmarkResult] = useState<Record<string, unknown> | null>(null);

Files Modified

  • src/hooks/useRuvLLM.ts - Rewrote WASM loading and type imports
  • src/components/RuvLLM.tsx - Fixed benchmarkResult type
  • vite.config.ts - Added esbuild top-level-await support
  • src/wasm/ - New directory for WASM files (copied from public/pkg)

Testing Setup Added

  • Playwright E2E tests: tests/e2e/ruvllm.spec.ts
  • Docker configuration: tests/e2e/Dockerfile, docker-compose.yml
  • Nginx config for production testing: tests/e2e/nginx.conf

Running Tests

# Install Playwright
npm run playwright:install

# Run tests locally
npm run test:playwright

# Run tests with UI
npm run test:playwright:ui

# Run tests in Docker
npm run test:playwright:docker

Build Status

✅ TypeScript compilation passes
✅ Vite build succeeds (176KB WASM binary)
✅ Dev server starts without errors

Remaining Work

  • Verify WASM loading in all browsers (Chrome, Firefox, Safari)
  • Run full Playwright test suite
  • Performance benchmarking across platforms
  • Consider code-splitting for the large index chunk (1.3MB)

Related

  • WASM binary optimized from 200KB to 176KB (12% reduction)
  • Using opt-level "z", strip symbols, feature-gated benchmarks
  • js_sys::Object used instead of serde_json for WASM size reduction

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions