Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

WebAssembly 2026: Chạy Rust/C++ Near-Native Speed Trong Browser Cho Dev Việt

Ếch Trendy
Ếch Trendy

5 tháng trước · 10 phút đọc

WebAssembly là gì và tại sao dev Việt nên quan tâm ngay bây giờ

Mình nhớ lần đầu thử build một physics simulation bằng JavaScript thuần. Frame rate chỉ đạt 12-15 FPS dù đã tối ưu đủ kiểu. Rồi mình thử compile sang WebAssembly - con số nhảy lên 60 FPS ổn định. Không thay đổi logic, không thêm server. Chỉ đổi cách code được compile.

Đó là câu trả lời ngắn nhất cho "Wasm là gì?": một định dạng binary instruction cho phép biên dịch Rust, C++, Go, Zig chạy near-native speed ngay trong browser, không cần plugin, không cần server xử lý.

343349 Wasm thay đổi game bằng cách biên dịch code, không interpret như JS

JS được interpret (hoặc JIT-compiled) - tức là browser phải đọc-hiểu-chạy code lúc runtime. Wasm thì khác: code đã được compile thành binary tối ưu trước, browser chỉ việc decode và chạy thẳng. Kết quả? CPU-heavy tasks như image processing, physics simulation, ML inference đạt speedup {{fact:fact_0}} so với JS thuần.

Đến 2026, Wasm không còn là "công nghệ thú vị để thử chơi" nữa. Figma dùng nó để tăng tốc load time {{fact:fact_1}}. Godot Engine export game WebAssembly ổn định. Component Model - chuẩn mới cho phép kết hợp module Wasm đa ngôn ngữ - đang được chuẩn hóa W3C. Nếu bạn build web app có tính toán nặng, đây là thứ cần biết.


Wasm hoạt động như thế nào: flow từ Rust đến browser

Bản chất của Wasm là một pipeline compile, không phải runtime magic. Hiểu flow này giúp bạn debug dễ hơn rất nhiều.

Bước 1: Viết code Rust/C++ như bình thường. Không có gì đặc biệt ở đây. Bạn vẫn viết struct, function, algorithm theo kiểu native.

Bước 2: Compile sang .wasm binary. Rust dùng wasm-pack hoặc cargo-component (toolchain mới 2026 cho Component Model). C++ dùng Emscripten. Output là file .wasm - binary nhỏ gọn, browser parse nhanh hơn asm.js khoảng 20 lần.

Bước 3: JS load và khởi tạo module. Browser VM decode module, expose functions qua JS interop. Với Rust, wasm-bindgen tự động generate JS glue code - bạn không cần viết tay.

Bước 4: Gọi Wasm từ JS như function bình thường. Heavy compute chạy trong Wasm. UI/DOM vẫn do JS xử lý.

343350 Phân chia rõ vai trò: Wasm lo tính toán, JS lo giao diện

Đây là ví dụ thực tế - một physics engine đơn giản bằng Rust với wasm-bindgen:

// Rust: physics engine biên dịch sang Wasm
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct PhysicsWorld {
    objects: Vec<(f32, f32, f32, f32)>, // x, y, vx, vy
}

#[wasm_bindgen]
impl PhysicsWorld {
    #[wasm_bindgen(constructor)]
    pub fn new() -> PhysicsWorld {
        PhysicsWorld { objects: Vec::new() }
    }

    // Thêm object vào simulation
    pub fn add_object(&mut self, x: f32, y: f32, vx: f32, vy: f32) {
        self.objects.push((x, y, vx, vy));
    }

    // Cập nhật physics mỗi frame - SIMD auto-optimized
    pub fn step(&mut self, dt: f32, gravity: f32) {
        for obj in &mut self.objects {
            obj.2 += 0.0;        // vx không thay đổi
            obj.3 -= gravity * dt; // vy giảm theo gravity
            obj.0 += obj.2 * dt;  // cập nhật x
            obj.1 += obj.3 * dt;  // cập nhật y
        }
    }

    // Trả về y của object đầu tiên để render
    pub fn get_y(&self, idx: usize) -> f32 {
        self.objects[idx].1
    }
}

Phía JS gọi như thế này:

// JS: khởi tạo Wasm module và chạy game loop
import init, { PhysicsWorld } from './pkg/physics_engine.js';

async function main() {
    await init(); // load .wasm binary

    const world = new PhysicsWorld();
    world.add_object(100, 500, 2.0, 10.0); // thêm quả bóng

    function gameLoop(timestamp) {
        world.step(0.016, 9.8); // step 16ms, gravity 9.8
        const y = world.get_y(0);
        renderBall(y); // JS lo việc render lên canvas
        requestAnimationFrame(gameLoop);
    }

    requestAnimationFrame(gameLoop);
}

main();

Game loop 60FPS smooth. Wasm xử lý toàn bộ physics calculation - phần tốn CPU nhất. JS chỉ nhận kết quả và vẽ lên canvas.

Một điểm cần nhớ: DOM calls qua JS bridge có overhead. Đừng gọi DOM liên tục từ Wasm - đó là anti-pattern phổ biến nhất. Wasm phù hợp với batch computation, không phải event handling.


Toolchain 2026: chọn gì để bắt đầu

Toolchain Wasm đang chia thành 2 nhánh chính tùy ngôn ngữ bạn dùng.

Nếu bạn dùng Rust - đây là combo tốt nhất hiện tại:

  • wasm-pack: build, test, publish package Wasm lên npm. Dùng cho browser apps với JS interop.
  • cargo-component: toolchain mới cho Component Model - chuẩn mới 2026 cho phép module Wasm compose với nhau bất kể ngôn ngữ gốc.
  • wasm-bindgen: tự động generate JS binding, hỗ trợ truyền Rust struct, enum sang JS.

Nếu bạn dùng C/C++ - Emscripten vẫn là lựa chọn số 1:

  • Compile nguyên dự án C++ (kể cả SDL2, OpenGL) sang Wasm.
  • Godot Engine dùng Emscripten để export game web - bạn build game bằng Godot, export ra .wasm + .html là xong.
  • SIMD và GC đã được optimize trong các phiên bản Emscripten gần đây.

343351 Chọn toolchain theo ngôn ngữ - không cần học lại từ đầu

Setup nhanh với Rust + wasm-pack:

# Cài Rust (nếu chưa có)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Thêm target WebAssembly
rustup target add wasm32-unknown-unknown

# Cài wasm-pack
cargo install wasm-pack

# Tạo project mới
wasm-pack new my-wasm-app
cd my-wasm-app

# Build ra pkg/ folder (JS + .wasm)
wasm-pack build --target web

Sau lệnh build, bạn có folder pkg/ chứa:

  • my_wasm_app_bg.wasm - binary module
  • my_wasm_app.js - JS glue code tự động generated
  • package.json - sẵn sàng dùng như npm package

Import vào bất kỳ JS/TS project nào: Vite, webpack, hoặc plain HTML đều được.

Về browser support: {{fact:fact_2}} Wasm core đã được support toàn bộ modern browsers. SIMD (quan trọng cho graphics/ML) support từ Chrome 91+, Firefox 89+, Safari 16.2+. Nếu bạn target user Việt chủ yếu dùng Chrome/Edge - không cần lo compatibility.

Một lưu ý thực tế: nếu bạn muốn học C++ để sau này dùng Emscripten, khóa Lập trình C++ cơ bản, nâng cao của F8 cover đủ nền tảng cần thiết trước khi nhảy vào compile sang Wasm.


Khi nào nên dùng Wasm - và khi nào thì không

Wasm không phải silver bullet. Mình từng thấy người replace toàn bộ JS bằng Wasm rồi app chậm hơn trước - vì dùng sai use case.

Dùng Wasm khi:

  • CPU-bound computation: Image processing, video encoding, physics simulation, hashing, compression, ML inference. Đây là sweet spot của Wasm, speedup thực tế {{fact:fact_3}} nếu critical path.
  • Port codebase C++/Rust sẵn có: Bạn có engine đang chạy native, muốn bring lên web mà không rewrite - Emscripten/wasm-pack làm điều này.
  • Deterministic performance: Wasm không có GC pauses như JS. Quan trọng với game loop, real-time audio processing.
  • ML inference tại browser: Run model ONNX/TensorFlow Lite trong Wasm, không cần gọi API server. User data không rời khỏi device.

Tránh Wasm khi:

  • DOM manipulation nhiều: Mỗi lần Wasm gọi sang JS để update DOM đều có overhead. Nếu logic chủ yếu là thay đổi UI, JS vẫn nhanh hơn.
  • Simple one-off calculations: Overhead khởi tạo module không đáng với computation nhỏ.
  • Team chưa có Rust/C++ background: Learning curve cao, đặc biệt với ownership model của Rust.

343352 Wasm thắng ở compute-heavy - JS vẫn tốt hơn cho DOM

Một case study thực tế cho dev Việt:

Bạn build web app xử lý ảnh (resize, filter, compress) phía client trước khi upload. JS Canvas API có thể làm nhưng chậm với ảnh lớn. Giải pháp:

// Rust: xử lý ảnh grayscale near-native speed
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn to_grayscale(pixels: &mut [u8]) {
    // Mỗi pixel: 4 bytes RGBA
    for chunk in pixels.chunks_mut(4) {
        let gray = (chunk[0] as u32 * 299
                  + chunk[1] as u32 * 587
                  + chunk[2] as u32 * 114) / 1000;
        chunk[0] = gray as u8; // R
        chunk[1] = gray as u8; // G
        chunk[2] = gray as u8; // B
        // chunk[3] giữ nguyên (alpha)
    }
}

JS lấy pixel data từ Canvas, truyền sang Wasm, nhận kết quả, render lại:

// Lấy pixel data từ canvas
const imageData = ctx.getImageData(0, 0, width, height);

// Truyền sang Wasm xử lý (shared memory - không copy)
const pixels = new Uint8Array(
    wasmMemory.buffer,
    pixelPtr,
    imageData.data.length
);
pixels.set(imageData.data);

// Gọi Wasm function
to_grayscale(pixelPtr, imageData.data.length);

// Render kết quả lên canvas
ctx.putImageData(new ImageData(pixels, width, height), 0, 0);

Kết quả: ảnh 4K xử lý trong vài chục milliseconds thay vì vài giây. Và bởi vì tất cả xảy ra tại browser, không cần upload lên server - tiết kiệm bandwidth và bảo mật hơn cho user.

Tải về checklist đánh giá use case Wasm để tham khảo trước khi quyết định integrate: {{resource:resource_0}}


Component Model và tương lai Wasm 2026

Nếu core Wasm giải quyết bài toán performance, Component Model giải quyết bài toán interoperability - cách các module Wasm từ ngôn ngữ khác nhau làm việc cùng nhau mà không cần JS làm trung gian.

Hình dung thế này: bạn có physics engine viết bằng Rust, rendering pipeline bằng C++, và business logic bằng Go. Trước đây, muốn combine 3 thứ này bạn phải viết JS bridge thủ công, quản lý memory qua lại giữa các module - rất mệt. Component Model định nghĩa chuẩn interface (WIT - Wasm Interface Types) để các module này giao tiếp trực tiếp, type-safe, không qua JS.

343353 Component Model: module đa ngôn ngữ giao tiếp trực tiếp, không cần JS bridge

Trong thực tế 2026, cargo-component cho Rust đã support Component Model. Bạn define interface bằng .wit file:

// physics.wit - interface definition
package my:physics;

interface world {
    record vec2 {
        x: f32,
        y: f32,
    }

    // Hàm step physics với delta time
    step: func(dt: f32) -> list<vec2>;
    add-object: func(pos: vec2, vel: vec2);
}

Rust implement interface này, C++ (qua Emscripten + WASI) consume nó - tất cả qua binary ABI chuẩn, không cần tự viết serialization/deserialization.

Roadmap 2026 đáng chú ý:

  • WasmGC Phase 4 (W3C standard từ tháng 4/2025): Garbage-collected languages như Kotlin, Dart compile sang Wasm tốt hơn. Flutter Web sẽ được hưởng lợi.
  • WASI Preview 2 stable: Wasm không chỉ chạy trên browser mà còn serverless functions, edge computing, IoT - với cùng một binary.
  • WASI Preview 3: Async I/O và threads - quan trọng cho server-side Wasm.
  • Thread support: Shared memory giữa Wasm workers - parallel computation trong browser.

Cộng đồng Wasm Việt Nam đang nhỏ nhưng đây chính xác là lúc để build expertise trước khi thị trường bão hòa. Các công ty game Việt, startup fintech cần xử lý số liệu real-time, hay team build creative tools đều là những use case phù hợp.

Tài liệu chính thức để theo dõi: {{resource:resource_0}} (Bytecode Alliance - tổ chức chủ lực đứng sau Wasm ecosystem) và {{resource:resource_1}} (rustwasm book - guide Rust + Wasm đầy đủ nhất).

Giờ bạn đã có đủ context để bắt đầu. Bước tiếp theo:

  1. Cài Rust + wasm-pack, chạy thử wasm-pack new hello-wasm
  2. Build physics hoặc image processing example nhỏ - đừng đợi project lớn
  3. Đo benchmark thực tế trên máy bạn: console.time() trước và sau khi switch sang Wasm

Nếu bạn chưa có nền tảng C++, khóa Lập trình C++ cơ bản, nâng cao trên F8 là điểm khởi đầu tốt - sau khi nắm C++ rồi học Emscripten sẽ dễ hơn nhiều.

Gặp vấn đề gì khi setup, drop comment - mình sẽ trả lời.