[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
---
|
||||
id: frontend-wasm-integration
|
||||
title: WebAssembly — Rust / Go / 통합
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [frontend, wasm, rust, vibe-coding]
|
||||
tech_stack: { language: "Rust / Go / TS", applicable_to: ["Frontend", "Backend"] }
|
||||
applied_in: []
|
||||
aliases: [WASM, WebAssembly, Rust wasm-bindgen, AssemblyScript, Wasmer, WIT]
|
||||
---
|
||||
|
||||
# WebAssembly
|
||||
|
||||
> JS 안 빠른 / native lib 사용. **Rust + wasm-bindgen 표준**. ML inference, image / video 처리, crypto, parser, regex. Browser + Node + Cloudflare Workers + WASI.
|
||||
|
||||
## 📖 핵심 개념
|
||||
- WASM: Binary instruction format.
|
||||
- wasm-bindgen: Rust ↔ JS 자동 binding.
|
||||
- WASI: WASM 의 system interface (file, network).
|
||||
- WIT (WebAssembly Interface Types): cross-language.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
### Rust → WASM
|
||||
```bash
|
||||
# Setup
|
||||
cargo new --lib my-wasm
|
||||
cd my-wasm
|
||||
```
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
[package]
|
||||
name = "my-wasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde-wasm-bindgen = "0.6"
|
||||
```
|
||||
|
||||
```rust
|
||||
// src/lib.rs
|
||||
use wasm_bindgen::prelude::*;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn fibonacci(n: u32) -> u64 {
|
||||
let mut a: u64 = 0; let mut b: u64 = 1;
|
||||
for _ in 0..n { let c = a + b; a = b; b = c; }
|
||||
a
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Stats { mean: f64, stddev: f64 }
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn analyze(data: &[f64]) -> JsValue {
|
||||
let mean = data.iter().sum::<f64>() / data.len() as f64;
|
||||
let variance = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / data.len() as f64;
|
||||
serde_wasm_bindgen::to_value(&Stats { mean, stddev: variance.sqrt() }).unwrap()
|
||||
}
|
||||
```
|
||||
|
||||
### Build
|
||||
```bash
|
||||
# wasm-pack
|
||||
cargo install wasm-pack
|
||||
wasm-pack build --target web
|
||||
|
||||
# 또는 bundler 통합
|
||||
wasm-pack build --target bundler
|
||||
|
||||
# Output: pkg/ folder with .wasm + JS glue
|
||||
```
|
||||
|
||||
### Use (browser)
|
||||
```ts
|
||||
import init, { fibonacci, analyze } from './pkg/my_wasm';
|
||||
|
||||
await init(); // load .wasm
|
||||
|
||||
console.log(fibonacci(50)); // 12586269025
|
||||
console.log(analyze([1.0, 2.0, 3.0])); // { mean: 2, stddev: 0.816 }
|
||||
```
|
||||
|
||||
### Vite plugin
|
||||
```ts
|
||||
// vite.config.ts
|
||||
import wasm from 'vite-plugin-wasm';
|
||||
import topLevelAwait from 'vite-plugin-top-level-await';
|
||||
|
||||
plugins: [wasm(), topLevelAwait()];
|
||||
```
|
||||
|
||||
```ts
|
||||
import init, { fibonacci } from './my_wasm';
|
||||
await init();
|
||||
```
|
||||
|
||||
### Use case 1: Image processing
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub fn blur(data: &[u8], width: u32, height: u32, radius: u32) -> Vec<u8> {
|
||||
// Gaussian blur
|
||||
let img = image::RgbaImage::from_raw(width, height, data.to_vec()).unwrap();
|
||||
image::imageops::blur(&img, radius as f32).into_raw()
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
const imageData = ctx.getImageData(0, 0, w, h);
|
||||
const blurred = blur(imageData.data, w, h, 5);
|
||||
ctx.putImageData(new ImageData(new Uint8ClampedArray(blurred), w, h), 0, 0);
|
||||
```
|
||||
|
||||
### ML inference (ONNX Runtime Web)
|
||||
```ts
|
||||
import * as ort from 'onnxruntime-web';
|
||||
|
||||
const session = await ort.InferenceSession.create('/model.onnx');
|
||||
const tensor = new ort.Tensor('float32', input, [1, 3, 224, 224]);
|
||||
const result = await session.run({ input: tensor });
|
||||
```
|
||||
|
||||
→ ResNet / YOLO 같은 모델 browser 안.
|
||||
|
||||
### Transformers.js
|
||||
```ts
|
||||
import { pipeline } from '@xenova/transformers';
|
||||
|
||||
const pipe = await pipeline('text-classification', 'Xenova/distilbert-base-uncased-finetuned-sst-2-english');
|
||||
const out = await pipe('I love this!');
|
||||
// [{ label: 'POSITIVE', score: 0.999 }]
|
||||
```
|
||||
|
||||
→ Hugging Face 모델 browser 직접.
|
||||
|
||||
### TensorFlow.js (WebGL / WebGPU)
|
||||
```ts
|
||||
import * as tf from '@tensorflow/tfjs';
|
||||
|
||||
const model = await tf.loadLayersModel('/model.json');
|
||||
const tensor = tf.tensor(input).reshape([1, 224, 224, 3]);
|
||||
const pred = model.predict(tensor) as tf.Tensor;
|
||||
```
|
||||
|
||||
### SQLite — sql.js / wasm-sqlite
|
||||
```ts
|
||||
import initSqlJs from 'sql.js';
|
||||
|
||||
const SQL = await initSqlJs({ locateFile: f => `/sql-wasm.wasm` });
|
||||
const db = new SQL.Database();
|
||||
db.run('CREATE TABLE users (id INTEGER, name TEXT)');
|
||||
db.run('INSERT INTO users VALUES (?, ?)', [1, 'Alice']);
|
||||
const result = db.exec('SELECT * FROM users');
|
||||
```
|
||||
|
||||
→ Browser 안 SQLite.
|
||||
|
||||
### Worker + WASM (offload main thread)
|
||||
```ts
|
||||
// worker.ts
|
||||
import init, { heavyWork } from './my_wasm';
|
||||
|
||||
self.onmessage = async (e) => {
|
||||
await init();
|
||||
const result = heavyWork(e.data);
|
||||
self.postMessage(result);
|
||||
};
|
||||
|
||||
// main.ts
|
||||
const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
|
||||
worker.postMessage(input);
|
||||
worker.onmessage = (e) => console.log(e.data);
|
||||
```
|
||||
|
||||
### WASI (server-side WASM)
|
||||
```bash
|
||||
# Wasmer / Wasmtime / Wasmer Edge
|
||||
wasmer run my-app.wasm
|
||||
```
|
||||
|
||||
```ts
|
||||
// Cloudflare Workers + WASM
|
||||
import wasmModule from './my_wasm.wasm';
|
||||
|
||||
export default {
|
||||
async fetch(req: Request): Promise<Response> {
|
||||
const instance = await WebAssembly.instantiate(wasmModule);
|
||||
return new Response(instance.exports.process(req));
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Component model (WIT)
|
||||
```wit
|
||||
// component.wit
|
||||
interface processor {
|
||||
process: func(input: list<u8>) -> list<u8>
|
||||
}
|
||||
```
|
||||
|
||||
→ Cross-language WASM components.
|
||||
|
||||
### Performance vs JS
|
||||
```
|
||||
간단 작업 (sum, fib): JS engine 도 빠름 — WASM 비슷
|
||||
복잡 / 메모리 intensive (image, ML, parser): WASM 5-50x 빠름
|
||||
SIMD 가능: WASM 더 빠름
|
||||
GC 객체 (string, array): JS ↔ WASM boundary 비용
|
||||
```
|
||||
|
||||
→ Hot path + 큰 데이터 = WASM. 일반 = JS.
|
||||
|
||||
### Bundle size
|
||||
```
|
||||
Rust + wasm-bindgen: 100KB-1MB 일반
|
||||
+ Streaming compile (instantiateStreaming) — 빠른 load
|
||||
|
||||
wasm-opt 로 size 줄이기.
|
||||
```
|
||||
|
||||
### AssemblyScript (TS-like → WASM)
|
||||
```ts
|
||||
// Rust 보다 친숙. 단 ecosystem 작음.
|
||||
export function fibonacci(n: i32): i64 {
|
||||
let a: i64 = 0, b: i64 = 1;
|
||||
for (let i = 0; i < n; i++) { const c = a + b; a = b; b = c; }
|
||||
return a;
|
||||
}
|
||||
```
|
||||
|
||||
### 디버그
|
||||
```ts
|
||||
// wasm-bindgen — console.log
|
||||
import { console_log } from 'wasm-bindgen';
|
||||
|
||||
console_log!("debug"); // browser DevTools
|
||||
```
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
log("from rust");
|
||||
```
|
||||
|
||||
### Build size + perf flags
|
||||
```toml
|
||||
[profile.release]
|
||||
opt-level = "z" # size (또는 3 = speed)
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
```
|
||||
|
||||
```bash
|
||||
wasm-opt -Oz -o optimized.wasm input.wasm
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준
|
||||
| 작업 | 추천 |
|
||||
|---|---|
|
||||
| Browser ML | Transformers.js / ONNX Runtime Web |
|
||||
| 이미지 처리 (blur, resize) | Rust + wasm-bindgen |
|
||||
| Crypto / hashing | WASM |
|
||||
| SQL in browser | sql.js |
|
||||
| Edge function (CF Workers) | WASM 가능 |
|
||||
| 일반 logic | JS — overhead 안 worth |
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **작은 작업 WASM**: JS-WASM boundary 비용 > 절약.
|
||||
- **Streaming compile 안 함**: 큰 .wasm 늦은 load.
|
||||
- **Memory copy 매 호출**: 큰 data — typed array share.
|
||||
- **Single-thread WASM main**: UI block. Worker.
|
||||
- **WASM bundle 분리 X**: 첫 load 큼. Dynamic import.
|
||||
- **Debug build prod**: 5-10x 큰. release.
|
||||
- **JS-WASM circular call**: stack / boundary 비용.
|
||||
|
||||
## 🤖 LLM 활용 힌트
|
||||
- Rust + wasm-bindgen + wasm-pack = 표준.
|
||||
- Vite plugin-wasm + top-level-await.
|
||||
- Worker 안 WASM + transferable data.
|
||||
- Hot path / 큰 data 만.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Web_OffMain_WebWorker]]
|
||||
- [[Perf_V8_Optimization]]
|
||||
- [[AI_Local_LLM_Inference]]
|
||||
Reference in New Issue
Block a user