Claude Code के साथ WebAssembly जोड़ना: Rust, wasm-pack और Vite
Claude Code से Rust WebAssembly को Vite में जोड़ें: image processing, CSV, typed wrapper, benchmark और pitfalls.
Claude Code और WebAssembly की सही भूमिका
WebAssembly, जिसे अक्सर Wasm कहा जाता है, एक portable binary format है। इसका मतलब है कि Rust, C या C++ में लिखा हुआ code browser या Node.js में चलाया जा सकता है। इसे JavaScript का पूरा replacement समझना गलत है। बेहतर तरीका यह है कि UI, DOM events, accessibility और state management TypeScript में रहें, और केवल भारी calculation वाले छोटे हिस्से Wasm में जाएं।
Claude Code इस काम में इसलिए मदद करता है क्योंकि Wasm integration सिर्फ एक Rust function नहीं है। इसमें wasm-pack build, wasm-bindgen से generated JavaScript glue, Vite loading, async initialization, TypeScript wrapper, benchmark और review prompt शामिल हैं। अगर prompt सिर्फ “Wasm से fast कर दो” होगा, तो code चल सकता है, लेकिन हर click पर init हो सकता है या JS-Wasm boundary बार-बार cross हो सकती है। JS-Wasm boundary वह जगह है जहां data JavaScript और WebAssembly के बीच जाता है।
इस guide में हम तीन छोटे लेकिन practical examples बनाएंगे: RGBA image buffer invert करना, CSV की numeric column sum करना, और bytes पर हल्का checksum निकालना। ये तीन patterns image processing, text parsing और binary processing को cover करते हैं। बाद में यही तरीका browser के अंदर तेज processing, पुराने Rust/C++ code को port करने, compression, custom codec या private data को server पर भेजे बिना calculate करने में काम आता है। Related performance reading के लिए Claude Code performance optimization भी देखें।
Official references साथ रखें: MDN WebAssembly, wasm-bindgen Guide, और wasm-pack repository। Claude Code से custom loader लिखवाने से पहले उसे इन boundaries का पालन करने को कहें।
Use case पहले तय करें
Wasm अपने आप fast नहीं होता। फायदा तब मिलता है जब एक बड़ा data block एक बार Wasm में जाए और वहां tight loop में process हो। नुकसान तब होता है जब JavaScript loop के अंदर छोटी Wasm function हजारों बार call होती है।
| Use case | Wasm क्यों fit है | Claude Code से क्या check कराएं |
|---|---|---|
| Image processing | RGBA buffer को loop में process करना आसान है | Memory copy, Canvas read/write, fair benchmark |
| Crypto, compression, codec | Byte arrays Rust libraries के साथ अच्छे चलते हैं | Audited library चाहिए या नहीं, custom code की सीमा |
| CSV और numeric calculation | Parsing और aggregation में repeat loops होते हैं | Empty rows, NaN, large files, error strategy |
| Rust/C++ asset porting | Existing logic browser में reuse हो सकती है | OS API, file I/O, threads, incompatible dependency |
| Browser-only heavy work | Sensitive data user device पर रह सकता है | Initial load size, fallback, target browsers |
Masa के छोटे experiments में सबसे अच्छा तरीका यह था कि पहले एक function Wasm में ले जाएं और फिर measure करें। Image processing में Rust function fast था, पर ImageData पढ़ना और वापस लिखना result को प्रभावित कर रहा था। CSV में हर line पर call करने से बेहतर था पूरा text एक बार pass करना।
wasm-pack के साथ छोटा Rust module
wasm-pack Rust crate को build करता है और wasm-bindgen के जरिए pkg folder बनाता है। इस folder में Wasm binary, JavaScript loader, package metadata और TypeScript declaration आते हैं। wasm-bindgen Rust function को JavaScript से call करने योग्य बनाता है।
# Cargo.toml
[package]
name = "wasm-lab"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
// src/lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn invert_rgba(pixels: &mut [u8]) {
for chunk in pixels.chunks_exact_mut(4) {
chunk[0] = 255 - chunk[0];
chunk[1] = 255 - chunk[1];
chunk[2] = 255 - chunk[2];
}
}
#[wasm_bindgen]
pub fn sum_csv_column(csv: &str, column: usize) -> f64 {
csv.lines()
.filter(|line| !line.trim().is_empty())
.filter_map(|line| line.split(',').nth(column))
.filter_map(|cell| cell.trim().parse::<f64>().ok())
.sum()
}
#[wasm_bindgen]
pub fn fnv1a32(bytes: &[u8]) -> u32 {
let mut hash = 0x811c9dc5u32;
for byte in bytes {
hash ^= u32::from(*byte);
hash = hash.wrapping_mul(0x01000193);
}
hash
}
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
wasm-pack build --target web --out-dir pkg
fnv1a32 security hash नहीं है। Password, signature, payment या token के लिए Web Crypto API या audited library use करें। यहां यह सिर्फ byte array example है।
Vite में load करें और typed wrapper बनाएं
Build के बाद pkg/wasm_lab.js और pkg/wasm_lab.d.ts बनते हैं। Vite में generated module import करें, init() का wait करें और एक TypeScript wrapper से safe API दें। इससे UI code Wasm loading detail से दूर रहता है।
// src/wasm-client.ts
import init, {
fnv1a32,
invert_rgba,
sum_csv_column,
} from "../pkg/wasm_lab";
export type WasmClient = {
invertImage(imageData: ImageData): Promise<ImageData>;
sumCsvColumn(csv: string, columnIndex: number): Promise<number>;
checksum(bytes: Uint8Array): Promise<number>;
};
let initPromise: Promise<void> | undefined;
async function ensureWasm(): Promise<void> {
initPromise ??= init().then(() => undefined);
return initPromise;
}
export const wasmClient: WasmClient = {
async invertImage(imageData) {
await ensureWasm();
const pixels = new Uint8Array(
imageData.data.buffer,
imageData.data.byteOffset,
imageData.data.byteLength,
);
invert_rgba(pixels);
return imageData;
},
async sumCsvColumn(csv, columnIndex) {
await ensureWasm();
return sum_csv_column(csv, columnIndex);
},
async checksum(bytes) {
await ensureWasm();
return fnv1a32(bytes);
},
};
// src/main.ts
import { wasmClient } from "./wasm-client";
const fileInput = document.querySelector<HTMLInputElement>("#csv-file");
const output = document.querySelector<HTMLPreElement>("#output");
fileInput?.addEventListener("change", async () => {
const file = fileInput.files?.[0];
if (!file || !output) return;
const csv = await file.text();
const total = await wasmClient.sumCsvColumn(csv, 2);
output.textContent = `column 2 total: ${total.toFixed(2)}`;
});
इस flow में पहले standard Vite config से शुरू करें। Raw .wasm import या अलग bundling strategy हो तभी plugin देखें। शुरुआती bug अक्सर path और init() timing से आते हैं।
Claude Code review prompt
Claude Code को implementation के बाद critical review भी कराना चाहिए। Review prompt में async init, memory copy, JS-Wasm boundary, DOM separation, types और verification commands साफ होने चाहिए।
Review only these files:
- src/lib.rs
- pkg/wasm_lab.d.ts
- src/wasm-client.ts
- src/main.ts
- src/bench.ts
Goal:
Integrate the Rust WebAssembly module into the Vite app without changing UI behavior.
Check:
1. init() is awaited before any exported Wasm function is called.
2. init() is cached and not repeated for every click or file upload.
3. Large arrays cross the JS-Wasm boundary at most once per user action.
4. DOM updates stay in TypeScript, not inside Rust.
5. The wrapper exposes typed methods and keeps generated pkg files out of hand edits.
6. Benchmarks compare the same input data for JavaScript and Wasm.
Run:
wasm-pack build --target web --out-dir pkg
npm run typecheck
npm run build
Team में यह rule CLAUDE.md में रखें। फिर हर Wasm change same review से गुजरेगा।
Benchmark और test steps
Wasm migration को feeling से approve न करें। Same input और same output measure करें।
// src/bench.ts
import { wasmClient } from "./wasm-client";
function invertJs(pixels: Uint8Array): void {
for (let index = 0; index < pixels.length; index += 4) {
pixels[index] = 255 - pixels[index];
pixels[index + 1] = 255 - pixels[index + 1];
pixels[index + 2] = 255 - pixels[index + 2];
}
}
function cloneImageData(source: Uint8Array, width: number, height: number): ImageData {
return new ImageData(new Uint8ClampedArray(source), width, height);
}
export async function runBench(): Promise<void> {
const width = 1920;
const height = 1080;
const source = new Uint8Array(width * height * 4);
crypto.getRandomValues(source);
const jsPixels = new Uint8Array(source);
const wasmImage = cloneImageData(source, width, height);
const jsStart = performance.now();
invertJs(jsPixels);
const jsMs = performance.now() - jsStart;
const wasmStart = performance.now();
await wasmClient.invertImage(wasmImage);
const wasmMs = performance.now() - wasmStart;
console.table({
javascriptMs: Number(jsMs.toFixed(2)),
wasmMs: Number(wasmMs.toFixed(2)),
ratio: Number((jsMs / wasmMs).toFixed(2)),
});
}
wasm-pack build --target web --out-dir pkg
npm run typecheck
npm run build
npm run dev
अगर Wasm result कमजोर है, तो Rust से पहले data conversion देखें। Canvas, ImageData, string copy और dev build result बदल सकते हैं। Output Claude Code को दें और पूछें कि Wasm रखें, Web Worker use करें या JavaScript optimize करें।
आम pitfalls
पहला pitfall async initialization है। init() पूरा होने से पहले exported function call नहीं होनी चाहिए। Wrapper में promise cache करें।
दूसरा pitfall bundle size है। हर Rust crate .wasm file बढ़ा सकता है। पहले एक function रखें और production build inspect करें।
तीसरा pitfall JS-Wasm boundary cost है। Small calls loop में न करें। Large array, string या buffer एक बार pass करें।
चौथा pitfall DOM को Wasm से control करना है। Events, rendering, accessibility और error messages TypeScript में रखें।
पांचवां pitfall hidden memory copy है। TypedArray, string और ImageData binding layer में copy हो सकते हैं। Benchmark में conversion cost भी शामिल करें।
छठा pitfall browser compatibility और security headers है। Basic Wasm widely supported है, लेकिन Wasm threads और SharedArrayBuffer के लिए COOP और COEP चाहिए। Ads, iframe या CDN वाले site में इसे जल्दी test करें।
Team workflow और consultation
Solo experiment के लिए यह code काफी है। Team में तय करें कि कौन सा logic Rust में जाएगा, क्या TypeScript में रहेगा, generated pkg files कैसे handle होंगी, कौन से browsers support होंगे और कौन सा benchmark merge रोक सकता है। यह सब CLAUDE.md में लिखें।
ClaudeCodeLab आपके repository पर Wasm use case चुनने, Rust/C++ asset review करने, benchmark design करने और team training करने में मदद कर सकता है। अगर WebAssembly production performance, privacy-sensitive browser processing या shared frontend architecture से जुड़ता है, तो Claude Code training and consultation से scope तय करना अच्छा रहेगा।
Verification note
इस flow को test करते समय सबसे पहले issue Rust में नहीं, Vite में init() wait करने की जगह पर आया। जब initialization wasm-client.ts में cache हुई, तब image, CSV और checksum एक ही path से चले। छोटे input में JavaScript काफी fast था; Full HD buffer और बड़े CSV में difference साफ दिखा। इसलिए केवल function body नहीं, पूरी JS-Wasm boundary measure करें।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code Permission Receipt Pattern: scope, proof और rollback लिखना
Claude Code के लिए permission receipt: allowed actions, approval boundary, verification commands, rollback note और revenue CTA checks।
Claude Code और Codex के लिए सुरक्षित Agent Harness: permissions, verification और rollback
Claude Code और Codex agents के लिए सुरक्षित harness: permissions, plan, verification और rollback.
Claude Code Subagents गाइड: article और code work को सुरक्षित तरीके से delegate करें
Claude Code subagents से article और code work बांटें: delegation rules, prompts, pitfalls, checklist और examples.