Web assembly

20 януари 2021

Административни неща

Административни неща

Web assembly

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.

Източник: https://webassembly.org/

Web assembly

Web assembly

Web assembly

Web assembly

Какво може да се компилира до web assembly

Какво може да се компилира до web assembly

Компилация на rust до wasm

Компилация на rust до wasm

Компилация на rust до wasm

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

std и no_std

Компилация на rust до wasm

std и no_std

Компилация на rust до wasm

std и no_std

Пример 1

Rust до Wasm

Cargo.toml

1 2
[lib]
crate-type = ["cdylib"]

Трябва проекта да се компилира като библиотека.
Тази библиотека ще се зареди от javascript код и ще се използват функциите дефинирани в нея.

Пример 1

Rust до Wasm

src/lib.rs

1 2 3 4
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
    a + b
}

Функцията add ще бъде достъпна от javascript

Пример 1

Rust до Wasm

1
cargo build --release --target wasm32-unknown-unknown

Това ше генерира target/wasm32-unknown-unknown/release/example_01.wasm

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Сървъра ще връща следните файлове:

1 2
cp target/wasm32-unknown-unknown/release/example_01.wasm \
    wasm_lib.wasm

Пример 1

Изпълняване в уеб браузър

index.html

1 2 3 4 5 6 7 8 9 10
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello wasm!</title>
  </head>
  <body>
    <script src="./index.js" type="module"></script>
  </body>
</html>

Пример 1

Изпълняване в уеб браузър

index.js

1 2 3 4 5 6
WebAssembly.instantiateStreaming(fetch('./wasm_lib.wasm'), {})
    .then(wasm => {
        // през `instance.exports` можем да достъпваме функциите,
        // които сме дефинирали в нашата библиотека.
        console.log("add(1, 2) = ", wasm.instance.exports.add(1, 2))
    })

Пример 1

Ограничения

Пример 1

Ограничения

Пример 1

Ограничения

Пример 1

Ограничения

Пример 1

Памет

Пример 1

Памет

Пример 1

Памет

Пример 1

Памет

Пример 1

Памет

Wasm bindgen

Необходима е програмата wasm-bindgen, която може да се инсталира през cargo

1
cargo install wasm-bindgen-cli

Необхидима е и библиотеката wasm-bindgen. Cargo.toml:

1 2
[dependencies]
wasm-bindgen = { version = "0.2.69", features = ["serde-serialize"] }

Wasm bindgen

Използване

1 2 3 4 5
cargo build --release --target wasm32-unknown-unknown

wasm-bindgen target/wasm32-unknown-unknown/release/wasm_lib.wasm \
    --out-dir pkg \
    --target web

Пример 2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add_i32(a: i32, b: i32) -> i32 {
    a + b
}

#[wasm_bindgen]
pub fn add_u32(a: u32, b: u32) -> u32 {
    a + b
}

#[wasm_bindgen]
pub fn greet() -> String {
    "hello wasm".to_string()
}

// `wasm_bindgen` атрибута позволява да подаваме структурата
// на JS код като opaque тип, т.е. указател
#[wasm_bindgen]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct User {
    name: String,
    age: u32,
}

#[wasm_bindgen]
impl User {
    // В този случай `User` е opaque type
    pub fn new(name: String, age: u32) -> User {
        User { name, age }
    }

    pub fn to_js_value(&self) -> JsValue {
        // Сериализира структурата до JSON и я подава на JS,
        // където ще се десериализира до JS обект
        JsValue::from_serde(self).unwrap()
    }
}

Пример 2

1 2 3 4 5 6 7 8 9 10 11 12
import { add_i32, add_u32, greet, User, default as init } from './pkg/wasm_lib.js'

init('./pkg/wasm_lib_bg.wasm')
    .then(_wasm => {
        console.log(greet())
        console.log("add_i32(-1, -2) = ", add_i32(-1, -2))  // -3
        console.log("add_u32(-1, -2) = ", add_u32(-1, -2))  // 4294967293

        const user = User.new("Иванчо", 10)
        console.log(user)               // Object { ptr: 1114144 }
        console.log(user.to_js_value()) // Object { name: "Иванчо", age: 10 }
    })

Реален пример от истински проект

Импортиране на функции от wasm

Wasm модул има достъп единсвено до функции, които са му подадени експлицитно от страна на JS при създаването му.

Импортиране на функции от wasm

Rust

1 2 3
extern "C" {
    pub fn setupCanvas();
}

Javascript

1 2 3 4 5 6 7 8 9 10
function setupCanvas() { /* ... */ }

const importObject = {
    env: { setupCanvas }
}

WebAssembly.instantiateStreaming(fetch('./wasm_lib.wasm'), importObject)
    .then(wasm => {
        /// ...
    })

Още един пример

Инструменти за wasm

wasm-pack

Инструменти за wasm

wasm-pack

Инструменти за wasm

wasm-pack

Инструменти за wasm

wasm-pack

Инструменти за wasm

wasm-pack

Инструменти за wasm

js-sys и web-sys


Оптимизации

Aко ще добавяме wasm към web страница обикновено размера на модула е по-важен критерий от скоростта му

Оптимизации

Aко ще добавяме wasm към web страница обикновено размера на модула е по-важен критерий от скоростта му

1 2 3 4
[profile.release]
opt-level = "z"
lto = "thin"
codegen-units = 1

Оптимизации

Aко ще добавяме wasm към web страница обикновено размера на модула е по-важен критерий от скоростта му

1 2 3 4
[profile.release]
opt-level = "z"
lto = "thin"
codegen-units = 1

Оптимизации

Aко ще добавяме wasm към web страница обикновено размера на модула е по-важен критерий от скоростта му

1 2 3 4
[profile.release]
opt-level = "z"
lto = "thin"
codegen-units = 1

Wasm извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб, намира и други приложения.
Web assembly като формат притежава някои удобни свойства:

Wasm извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб, намира и други приложения.
Web assembly като формат притежава някои удобни свойства:

Wasm извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб, намира и други приложения.
Web assembly като формат притежава някои удобни свойства:

Wasm извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб, намира и други приложения.
Web assembly като формат притежава някои удобни свойства:

Wasm извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб, намира и други приложения.
Web assembly като формат притежава някои удобни свойства:

Wasm извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб, намира и други приложения.
Web assembly като формат притежава някои удобни свойства:

Wasm извън браузъра

wasm_docker_tweet

Watt

Vscode tree sitter plugin

Lunatic

Въпроси