Пробуем делать web-frontend на Rust (WebAssembly)

в 8:12, , рубрики: chrome, Firefox, javascript, Rust, wasm, webassembly, Клиентская оптимизация, Разработка веб-сайтов

Пробуем делать web-frontend на Rust (WebAssembly) - 1 Недавно вышла новость про то, что webassembly теперь включен в firefox 52 из коробки. А потом еще и chrome 57 подтянулся (правда, там вроде бы были какие-то баги с запуском). Я решил, что обязательно надо попробовать.

Для тех, кто не знает, что такое webassembly краткая информация: webassembly (или wasm) — это низкоуровневый язык, который понимают браузеры, и в который можно будет скомпилировать программы, написанные на популярных языках. Это гораздо более выгодно по скорости парсинга и выполнения, чем компилировать эти языки в чистый javascript или какой-нибудь asm.js.

Wasm задумывался в основном для c/c++, но, на удивление, уже все готово, чтобы скомпилировать программу на rust. Давайте сделаем небольшое приложение и посмотрим, что получится. Все это будем компилировать на Ubuntu. Без теоретических деталей, просто "пощупаем".

Устанавливаем Rust и emscripten SDK

Для начала нам понадобится rustup. Это инструмент для установки как самого rust компилятора, так и других вещей из rust мира.

curl https://sh.rustup.rs -sSf | sh

При установке в ваш ~.profile будет прописан путь до бинарников cargo, но чтобы не перелогиниваться прямо сейчас, можно просто выполнить команду source $HOME/.cargo/env.

Теперь нам надо добавить нужный target

rustup install stable
rustup default stable
rustup target add wasm32-unknown-emscripten

emscripten — это такой LLVM-to-javascript компилятор. Также умеет генерить и wasm. (Как известно, Rust использует llvm).

Надо скачать и распаковать sdk для этого дела. Качаем файл emsdk-portable.tar.gz со страницы http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#sdk-downloads

Примерно так:

mkdir emsdk
cd emsdk
wget "https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz"
tar -xzf emsdk-portable.tar.gz
cd emsdk_portable
source emsdk_env.sh

Далее надо это дело скомпилировать. Предупреждаю, это может занять пару часов, причем с диким выжиранием процессора и памяти.

emsdk update
emsdk install sdk-incoming-64bit
emsdk activate sdk-incoming-64bit

emsdk предложит еще раз выполнить
source ./emsdk_env.sh

Hello, world

Сделаем простенький хелловорлд на расте

fn main() {
    println!("============nHello, worldn===============");
}

И скомпилируем

rustc --target=wasm32-unknown-emscripten wasmtest.rs

Компилятор создаст файл wasmtest.wasm, а также js-обвязку для загрузки этого файла (wasmtest.js), потому что пока что нельзя просто взять и написать <script src="wasmtest.wasm">

Теперь нам надо сделать простую html-страницу для этого дела.

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8" />
    <title>Rust Wasm</title>
</head>
<body>
<script type='text/javascript'>
    var Module = {};
    fetch('wasmtest.wasm').then(response =>
        response.arrayBuffer()
    ).then(buffer => {
        Module.wasmBinary = buffer;
        const script = document.createElement('script');
        script.src = "wasmtest.js";
        document.body.appendChild(script);
    });
</script>
</body>
</html>

Чтобы посмотреть результат, проще всего запустить http-сервер на python, он не требует никакой конфигурации

python -m SimpleHTTPServer

Запустив в браузере (лучше в firefox) http://localhost:8000/hello.html вы увидите в консоли надпись "Hello, world!".

Доступ к DOM

Консоль — это здорово, но хотелось бы что-то на странице отобразить, для этого нужны какие-то функции работы с DOM. Сначала я зарылся в мозгодробительную документацию, но потом выяснил, что всё уже написано до нас. Есть библиотека webplatform, которая предоставляет какие-то базовые вещи для работы с DOM.

Перепишем нашу программу:

extern crate webplatform;

fn main() {
    println!("============nHello, worldn===============");
    let document = webplatform::init();
    let body = document.element_query("body").unwrap();
    body.html_set("<h1>Привет, я web assembly!</h1> <button>Нажми меня</button>");
    let button = document.element_query("button").unwrap();
    button.on("click", |_| webplatform::alert("Кнопка нажата!"));
}

Весь проект можете посмотреть на github

Собрать его можно так:

cargo build --target=wasm32-unknown-emscripten
rustc --target=wasm32-unknown-emscripten src/wasmtest.rs -L target/wasm32-unknown-emscripten/debug/deps/ 

(Я не особо знаток раста, так что если это можно сделать в одну команду cargo, подскажите плиз).

Потом запускаем наш питон-сервер

python -m SimpleHTTPServer

И смотрим в firefox http://localhost:8000/hello.html. Должно получиться примерно так, как на КДПВ.

Скомпилированные файлы и hello.html тоже лежат в репозитории, так что вы можете просто пощупать результат у себя, не заморачиваясь с компиляцией.

Выводы и перспективы

Понятно, что сейчас всё сырое, неудобное и с багами, но у webassembly несомненно большое будущее. Всё, что требует сложных вычислений, можно будет перенести из javascript на wasm. Появятся тяжелые программы в вебе, о которых мы сейчас и мечтать не можем. Навороченные игры? Обработка видео и звука? Кто знает.

Куча библиотек на c, c++, rust и т.д. будет перенесена на веб в виде wasm-модулей.

Появились энтузиасты, которые хотят ускорить reactjs засчет rust и wasm (ссылка).

Появится закрытый проприетарный код. Если js, пропущенный через uglifyjs еще как-то можно читать, то c wasm это будет сделать гораздо сложнее.

Как всегда, добро пожаловать в коменты. Что думаете вы?

Автор: Антон Околелов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js