company_banner

Yew — Rust&WebAssembly-фреймворк для фронтенда

    Yew — аналог React и Elm, написанный полностью на Rust и компилируемый в честный WebAssembly. В статье Денис Колодин, разработчик Yew, рассказывает о том, как можно создать фреймворк без сборщика мусора, эффективно обеспечить immutable, без необходимости копирования состояния благодаря правилам владения данными Rust, и какие есть особенности при трансляции Rust в WebAssembly.



    Пост подготовлен по материалам доклада Дениса на конференции HolyJS 2018 Piter. Под катом — видео и текстовая расшифровка доклада.


    Денис Колодин работает в компании Bitfury Group, которая занимается разработкой различных блокчейн-решений. Уже более двух лет он кодит на Rust — языке программирования от Mozilla Research. За это время Денис успел основательно изучить этот язык и использовать его для разработки различных системных приложений, бэкенда. Сейчас же, в связи с появлением стандарта WebAssembly, стал смотреть и в сторону фронтенда.

    Agenda


    Сегодня мы с вами узнаем о том, что такое Yew (название фреймворка читается так же, как английское слово «ты» — you; «yew» — это дерево тис в переводе с английского).

    Немного поговорим об архитектурных аспектах, о том, на каких идеях построен фреймворк, о возможностях, которые в него заложены, а также об особенностях, которые нам дополнительно дает Rust по сравнению с другими языками.

    В конце я расскажу, как начать использовать Yew и WebAssembly прямо сегодня.

    Что такое Yew?


    В первую очередь, это WebAssembly, т.е. исполняемый байт-код, который работает в браузерах. Он нужен для того, чтобы на стороне пользователя запускать сложные алгоритмы, например, криптографию, кодирование/декодирование. Проще реализовать это на системных языках, чем прикручивать костыли.

    WebAssembly — это стандарт, который четко описан, понятен и поддерживается всеми современными браузерами. Он позволяет использовать различные языки программирования. И это интересно в первую очередь тем, что вы можете повторно применять код, созданный комьюнити на других языках.

    При желании на WebAssembly можно полностью написать приложение, и Yew это позволяет сделать, но важно не забывать, что даже в этом случае JavaScript остается в браузере. Он необходим, чтобы подготовить WebAssembly — взять модуль (WASM), добавить к нему окружение и запустить. Т.е. без JavaScript не обойтись. Поэтому WebAssembly имеет смысл рассматривать скорее как расширение, а не революционную альтернативу JS.

    Как выглядит разработка




    У вас есть исходник, есть компилятор. Вы это все транслируете в бинарный формат и запускаете в браузере. Если браузер старый, без поддержки WebAssembly, то потребуется emscripten. Это, грубо говоря, эмулятор WebAssembly для браузера.

    Yew — готовый к использованию wasm framework


    Перейдем к Yew. Я разработал этот фреймворк в конце прошлого года. Тогда я писал на Elm некое криптовалютное приложение и столкнулся с тем, что из-за ограничений языка не могу создать рекурсивную структуру. И в этот момент подумал: в Rust моя проблема решилась бы очень легко. А так как 99% времени я пишу на Rust и просто обожаю этот язык именно за его возможности, то решил поэкспериментировать — скомпилировать приложение с такой же update-функцией в Rust.

    Первый набросок занял у меня несколько часов, пришлось разобраться, как скомпилировать WebAssembly. Я его запустил и понял, что буквально за несколько часов заложил ядро, которое очень легко развить. Мне потребовалось еще буквально несколько дней, чтобы довести все это до минимального движка фреймворка.

    Я выложил его в open source, но не рассчитывал, что он будет сколько-нибудь популярным. Однако на сегодня он собрал более 4 тысяч звезд на GitHub. Посмотреть проект можно по ссылке. Там же есть множество примеров.

    Фреймворк полностью написан на Rust. Yew поддерживает компиляцию прямо в WebAssembly (wasm32-unknown-unknown target) без emscripten. При необходимости можно работать и через emscripten.

    Архитектура


    Теперь несколько слов о том, чем фреймворк отличается от традиционных подходов, которые существуют в мире JavaScript.

    Для начала покажу, с какими ограничениями языка я столкнулся в Elm. Возьмем случай, когда есть модель и есть сообщение, которое позволяет эту модель трансформировать.

    type alias Model = 
        { value : Int 
        } 
      
    type Msg 
        = Increment 
        | Decrement 
    

    case msg of 
        Increment -> 
          { value = model.value + 1 } 
        Decrement -> 
          { value = model.value - 1 }
    

    В Elm мы просто создаем новую модель и отображаем ее на экране. Предыдущая версия модели остается неизменяемой. Почему я на этом делаю акцент? Потому что в Yew модель является mutable, и это один из самых частых вопросов. Далее я поясню, почему так сделано.

    Изначально я шел по классическому пути, когда модель создавалась заново. Но по мере развития фреймворка увидел, что нет смысла хранить предыдущую версию модели. Rust позволяет отследить время жизни всех данных, изменяемые они или нет. И поэтому я могу изменять модель безопасно, зная, что Rust контролирует отсутствие конфликта.

    struct Model { 
        value: i64, 
    } 
      
    enum Msg { 
        Increment, 
        Decrement, 
    } 
    

    match msg { 
        Msg::Increment => { 
            self.value += 1; 
        } 
        Msg::Decrement => { 
            self.value -= 1; 
        } 
    }
    

    Это первый момент. Второй момент: зачем нам нужна старая версия модели? В том же Elm вряд ли существует проблема какого-то конкурентного доступа. Старая модель нужна только для того, чтобы понять, когда производить рендеринг. Осознание этого момента позволило мне полностью избавиться от immutable и не хранить старую версию.



    Посмотрите на вариант, когда у нас есть функция update и два поля — value и name. Есть значение, которое сохраняется, когда мы вводим в поле input данные. Модель изменяется.



    Важно, что в рендеринге значение value не участвует. И поэтому мы его можем изменять сколько угодно. Но нам не нужно влиять на DOM-дерево и не нужно инициировать эти изменения.

    Это натолкнуло меня на мысль о том, что только разработчик может знать правильный момент, когда действительно нужно инициировать рендеринг. Для инициации я стал использовать флаг — просто булево значение — ShouldRender, который сигнализирует о том, что модель изменилась и нужно запускать рендеринг. При этом нет никаких накладных расходов на постоянные сравнения, нет расхода памяти — приложения, написанные на Yew, максимально эффективны.

    В примере выше не произошло вообще никакого выделения памяти, кроме как на сообщение, которое было сгенерировано и отправлено. Модель сохранила свое состояние, а на рендеринге это отразилось только с помощью флага.

    Возможности


    Написание фреймворка, который работает в WebAssembly, — непростая задача. У нас есть JavaScript, но он должен создать некое окружение, с которым нужно взаимодействовать, и это огромный объем работы. Первоначальная версия этих связок выглядела примерно так:



    Я взял демонстрацию из другого проекта. Есть много проектов, которые идут по этому пути, но он быстро заводит в тупик. Ведь фреймворк — достаточно крупная разработка и приходится писать много стыковочного кода. Я стал использовать в Rust библиотеки, которые называют крейтами, в частности, крейт Stdweb.

    Интегрированный JS


    С помощью Rust-макросов можно расширять язык — в Rust-код мы можем вставлять куски JavaScript, это очень полезная фича языка.

    let handle = js! { 
        var callback = @{callback}; 
        var action = function() { 
            callback(); 
        }; 
        var delay = @{ms}; 
        return { 
            interval_id: setInterval(action, delay), 
            callback: callback, 
        }; 
    }; 
    

    Использование макросов и Stdweb позволило мне быстро и эффективно написать все нужные связки.

    JSX шаблоны


    Вначале я пошел по пути Elm и начал использовать шаблоны, реализованные с помощью кода.

    fn view(&self) -> Html<Context, Self> { 
        nav("nav", ("menu"), vec![ 
            button("button", (), ("onclick", || Msg::Clicked)), 
            tag("section", ("ontop"), vec![ 
                p("My text...") 
            ]) 
        ]) 
    }
    

    Я никогда не был сторонником React. Но когда стал писать свой фреймворк, то понял, что JSX в React — это очень крутая штука. Тут очень удобное представление кодовых темплейтов.

    В итоге я взял макрос на Rust и внедрил прямо внутрь Rust возможность писать HTML-разметку, которая сразу генерирует элементы виртуального дерева.

    impl Renderable<Context, Model> for Model { 
        fn view(&self) -> Html<Context, Self> { 
            html! { 
                <div> 
                    <nav class="menu",> 
                        <button onclick=|_| Msg::Increment,>{ "Increment" }</button> 
                        <button onclick=|_| Msg::Decrement,>{ "Decrement" }</button> 
                    </nav> 
                    <p>{ self.value }</p> 
                    <p>{ Local::now() }</p> 
                </div> 
            } 
        } 
    } 
    

    Можно сказать, что JSX-подобные шаблоны — это чистые кодовые шаблоны, но на стероидах. Они представлены в удобном формате. Также обратите внимание, что здесь я прямо в кнопку вставляю Rust-выражение (Rust-выражение можно вставлять внутрь этих шаблонов). Это позволяет очень тесно интегрироваться.

    Компоненты с честной структурой


    Дальше я стал развивать шаблоны и реализовал возможность использования компонент. Это первый issue, который был сделал в репозитории. Я реализовал компоненты, которые могут использоваться в коде шаблона. Вы просто объявляете честную структуру на Rust и пишете для нее некоторые свойства. И эти свойства можно задавать прямо из шаблона.



    Еще раз отмечу важную вещь, что эти шаблоны являются честно сгенерированным Rust-кодом. Поэтому любая ошибка здесь будет замечена компилятором. Т.е. вы не сможете ошибиться, как это часто бывает в JavaScript-разработке.

    Типизированные области


    Другая интересная особенность заключается в том, что, когда компонент помещается внутрь другого компонента, он может видеть тип сообщений родителя.



    Компилятор жестко связывает эти типы и не даст вам возможности ошибиться. При обработке событий сообщения, которые ожидает или может отправлять компонент, должны будут полностью соответствовать родителю.

    Другие возможности


    Из Rust прямо во фреймворк я перенес реализацию, позволяющую удобно использовать различные форматы сериализации / десериализации (снабдив ее дополнительными обертками). Ниже представлен пример: мы обращаемся в local storage и, восстанавливая данные, указываем некую обертку — что мы ожидаем тут json.

    Msg::Store => { 
        context.local_storage.store(KEY, Json(&model.clients)); 
    } 
    Msg::Restore => { 
         if let Json(Ok(clients)) = context.local_storage.restore(KEY) { 
             model.clients = clients; 
        } 
    }
    

    Здесь может быть любой формат, в том числе бинарный. Соответственно, сериализация и десериализация становятся прозрачными и удобными.

    Идея другой возможности, которую я реализовал, пришла от пользователей фреймворка. Они попросили сделать фрагменты. И вот здесь я столкнулся с интересной вещью. Увидев в JavaScript возможность вставлять фрагменты в DOM-дерево, я сначала решил, что реализовать такую функцию в моем фреймворке будет очень легко. Но попробовал эту опцию, и оказалось, что она не работает. Пришлось разбираться, ходить по этому дереву, смотреть, что там изменилось и т.п.

    Во фреймворке Yew используется виртуальное DOM-дерево, все изначально существует в нем. Фактически, когда появляются какие-то изменения в шаблоне, они превращаются в патчи, которые уже изменяют отрендеренное DOM-дерево.

    html! { 
        <> 
            <tr><td>{ "Row" }</td></tr> 
            <tr><td>{ "Row" }</td></tr> 
            <tr><td>{ "Row" }</td></tr> 
        </> 
    }
    

    Дополнительные преимущества


    Rust предоставляет еще много разных сильных возможностей, я расскажу лишь о самых важных.

    Сервисы: взаимодействие с внешним миром


    Первая возможность, о которой хочу сказать, — это сервисы. Необходимый функционал вы можете описать в виде некоторого сервиса, опубликовать его в виде крейта и повторно использовать.

    В Rust очень качественно реализована возможность создания библиотек, их интеграции, стыковки и склейки. Фактически, вы можете создать различные API для взаимодействия с вашим сервисом, в том числе JavaScript-овые. При этом фреймворк может взаимодействовать с внешним миром, несмотря на то, что он работает внутри WebAssembly рантайма.

    Примеры сервисов:

    • TimeOutService;
    • IntervalService;
    • FetchService;
    • WebSocketService;
    • Custom Services…

    Сервисы и крейты Rust: crates.io.

    Контекст: заявите требования


    Другая вещь, которую я реализовал во фреймворке не совсем традиционно, это контекст. В React есть Context API, я же использовал Context в ином понимании. Фреймворк Yew состоит из компонентов, которые вы делаете, а Context — это некоторое глобальное состояние. Компоненты могут не учитывать это глобальное состояние, а могут предъявлять некоторые требования — чтобы глобальная сущность соответствовала каким-то критериям.

    Допустим, наш абстрактный компонент требует возможности выгрузки чего-то на S3.



    Внизу видно, что он использует эту выгрузку, т.е. отправляет данные в S3. Такой компонент можно выложить в виде крейта. Пользователь, который этот компонент скачает и добавит внутрь шаблона в свое приложение, столкнется с ошибкой — компилятор у него спросит, где поддержка S3? Пользователь должен будет эту поддержку реализовать. После этого компонент автоматически начинает жить полноценной жизнью.

    Где это нужно? Представьте: вы создаете компонент с хитрой криптографией. У него есть требования, что окружающий контекст должен позволять ему куда-то логиниться. Все, что вам  нужно сделать, это добавить в шаблоне форму авторизации и в вашем контексте реализовать связь именно с вашим сервисом. Т.е. это будет буквально три строчки кода. После этого компонент начинает работать.

    Представим, что у нас десятки различных компонент. И они все имеют одно и то же требование. Это позволяет один раз реализовать какой-то функционал, чтобы оживить все компоненты и подтягивать данные, которые нужны. Прямо из контекста. И компилятор вам не позволит ошибиться: если у вас не реализован интерфейс, который требует компонент, ничего не заработает.

    Поэтому можно легко создавать весьма привередливые кнопки, которые будут просить некоторые API или иные возможности. Благодаря Rust и системе этих интерфейсов (они называются trait в Rust-е) появляется возможность задекларировать требования компонента.

    Компилятор не даст вам ошибиться


    Представим, что мы создаем компонент с некоторыми свойствами, одно из которых — возможность установить call back. И, например, мы установили свойство и пропустили одну букву в его названии.



    Пытаемся скомпилировать, Rust на это реагирует быстро. Он говорит, что мы ошиблись и такого свойства нет:



    Как видите, Rust прямо использует этот шаблон и может внутри макроса делать рендеринг всех ошибок. Он подсказывает, как на самом деле должно было называться свойство. Если вы прошли компилятор, то глупых рантайм-ошибок вроде опечаток у вас не будет.

    А теперь представим, у нас есть кнопка, которая просит, чтобы наш глобальный контекст умел подключаться к S3. И создаем контекст, который не реализует поддержку S3. Посмотрим, что будет.



    Компилятор сообщает, что мы вставили кнопку, но этот интерфейс не реализован для контекста.



    Остается только зайти в редактор, добавить в контекст связь с Amazon, и все заведется. Вы можете создать уже готовые сервисы с каким-то API, потом просто добавлять в контекст, подставлять на него ссылку — и компонент сразу же оживает. Это позволяет вам делать очень классные вещи: вы добавляете компоненты, создаете контекст, набиваете его сервисами. И все это работает полностью автоматически, нужны минимальные усилия на то, чтобы это все связать.

    Как начать использовать Yew?


    С чего начать, если вы хотите попробовать скомпилировать WebAssembly приложение? И как это можно сделать с помощью фреймворка Yew?

    Rust-to-wasm компиляция


    Первое — вам потребуется установить компилятор. Для этого есть инструмент rustup:

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

    Плюс, вам может потребоваться emscripten. Для чего он может быть полезен? Большинство библиотек, которые написаны для системных языков программирования, особенно для Rust (изначально системного), разработаны под Linux, Windows и другие полноценные операционки. Очевидно, что в браузере многих возможностей нет.

    Например, генерация случайных чисел в браузере делается не так, как в Linux. emscripten вам пригодится, если вы хотите использовать библиотеки, которые требуют системный API.

    Библиотеки и вся инфраструктура потихонечку переходят на честный WebAssembly, и emscripten подкладывать уже не требуется (используются JavaScript-овые возможности для генерации случайных чисел и других вещей), но если вам нужно собрать то, что пока совсем в браузере не поддерживается, без emscripten не обойтись.

    Также рекомендую использовать cargo-web:

    cargo install cargo-web

    Есть возможность скомпилировать WebAssembly без дополнительных утилит. Но cargo-web — классный инструмент, который дает сразу несколько вещей, полезных для JavaScript-разработчиков. В частности, он будет следить за файлами: если вы вносите какие-то изменения, он начнет сразу компилировать (компилятор таких функций не предоставляет). В этом случае Cargo-web позволит вам ускорить разработку. Есть разные системы сборки под Rust, но cargo — это 99,9% всех проектов.

    Новый проект создается следующим образом:

    cargo new --bin my-project

    [package]
    name = "my-project"
    version = "0.1.0"
     
    [dependencies]
    yew = "0.3.0"

    Дальше просто стартуете проект:

    cargo web start --target wasm32-unknown-unknown

    Я привел пример честного WebAssembly. Если вам нужно скомпилировать под emscripten (rust-компилятор может сам подключить emscripten), в самом последнем элементе unknown можно вставить слово emscripten, что позволит вам использовать больше крейтов. Не забывайте, что emscripten  - это достаточно большой дополнительный обвес к вашему файлу. Поэтому лучше писать честный WebAssembly-код.

    Существующие ограничения


    Того, кто имеет опыт кодинга на системных языках программирования, существующие во фреймворке ограничения могут расстроить. Далеко не все библиотеки можно использовать в WebAssembly. Например, в JavaScript-окружении нет потоков. WebAssembly в принципе не декларирует этого, и вы, конечно, можете его использовать в многопоточной среде (это вопрос открытый), но JavaScript — это все-таки однопоточная среда. Да, есть воркеры, но это изоляция, поэтому никаких потоков там не будет.

    Казалось бы, без потоков можно жить. Но если вы захотите использовать библиотеки, основанные на потоках, например, захотите добавить какой-то рантайм, это может не взлететь.

    Также здесь нет никакого системного API, кроме того, который вы из JavaScript перенесете в WebAssembly. Поэтом многие библиотеки не перенесутся. Писать и читать напрямую файлы нельзя, сокеты открыть нельзя, в сеть писать нельзя. Если вы хотите например, сделать web-socket, его надо притащить из JavaScript.

    Другой недостаток заключается в том, что отладчик WASM существует, но его никто не видел. Он пока находится в таком сыром состоянии, что вряд ли будет вам полезен. Поэтому отладка WebAssembly — это сложный вопрос.

    При использовании Rust практически все рантайм-проблемы будут связаны с ошибками в бизнес-логике, их будет легко исправить. Но очень редко появляются баги низкого уровня — например, какая-то из библиотек неправильно делает стыковки — и это уже сложный вопрос. К примеру, на текущий момент существует такая проблема: если я компилирую фреймворк с emscripten и там есть изменяемая ячейка памяти, владение которой то забирается, то отдается, emscripten где-то посередине разваливается (и я даже не уверен, что это emscripten). Знайте, если наткнетесь на проблему где-то в middleware на низком уровне, то починить это будет на текущий момент непросто.

    Будущее фреймворка


    Как будет дальше развиваться Yew? Я вижу его основное предназначение в создании монолитных компонент. У вас будет скомпилированный WebAssembly-файл, и вы его будете просто вставлять в приложение. Например, он может предоставлять криптографические возможности, рендеринг или редактирование.

    Интеграция с JS


    Будет усиливаться интеграции с JavaScript. На JavaScript-е написано большое количество классных библиотек, которыми удобно пользоваться. И в репозитории есть примеры, где я показываю, как можно использовать существующую JavaScript библиотеку прямо из фреймворка Yew.

    Типизированный CSS


    Поскольку используется Rust, очевидно, что можно добавить типизированный CSS, который можно будет сгенерировать таким же макросом, что в примере JSX-подобного шаблонизатора. При этом компилятор будет проверять, например, не присвоили ли вы вместо цвета какой-то иной атрибут. Это сбережет тонны вашего времени.

    Готовые компоненты


    Также я смотрю в направлении создания готовых к использованию компонент. На фреймворке можно сделать крейты, которые будут предоставлять, например, набор каких-то кнопок или элементов, которые будут подключаться в виде библиотеки, добавляться в шаблоны и использоваться.

    Улучшение производительности в частных случаях


    Производительность — это очень тонкий и сложный вопрос. Быстрее ли работает WebAssembly по сравнению с JavaScript? У меня нет никакого пруфа, подтверждающего положительный или отрицательный ответ. По ощущениям и по некоторым совсем простым тестам, которые я проводил, WebAssembly работает очень быстро. И у меня есть полная уверенность, что его производительность будет выше, чем у JavaScript, только потому, что это низкоуровневый байт-код, где не требуется выделение памяти и много других требующих ресурсы моментов.

    Больше контрибьюторов


    Я бы хотел привлечь больше контрибьюторов. Двери для участия во фреймворке всегда открыты. Каждый, кто хочет что-то модернизировать, разобраться в ядре и трансформировать тот инструментарий, с которым работает большое число разработчиков, может легко подключаться и предлагать свои правки.

    В проекте поучаствовало уже много контрибьюторов. Но Core-контрибьюторов на текущий момент нет, потому что для этого нужно понимать вектор развития фреймворка, а он пока четко не сформулирован. Но есть костяк, ребята, кто сильно разбирается в Yew — порядка 30 человек. Если вы тоже захотите что-то добавить во фреймворк, всегда пожалуйста, отправляйте pull request.

    Документация


    Обязательный пункт в моих планах — создание большого количества документации о том, как писать приложения на Yew. Очевидно, что подход к разработке в данном случае отличается от того, что мы видели в React и Elm.

    Мне иногда ребята показывают интересные кейсы, как можно использовать фреймворк. Все-таки создать фреймворк — не то же самое, что профессионально на нем писать. Практики использования фреймворка еще только формируются.

    Попробуйте, установите Rust, расширьте свои возможности как разработчика. Освоение WebAssembly будет полезно каждому из нас, потому что создание очень сложных приложений — тот момент, которого мы уже давно ждем. Иными словами, WebAssembly — это не только про веб-браузер, а это вообще рантайм, который точно развивается и будет развиваться еще активнее.

    Если доклад понравился, обратите внимание: 24-25 ноября в Москве состоится новая HolyJS, и там тоже будет много интересного. Уже известная информация о программе — на сайте, и билеты можно приобрести там же (с первого октября цены повысятся).
    JUG Ru Group
    Конференции для программистов и сочувствующих. 18+

    Comments 22

      +3
      Сколько весит Hello World?
        0
        в WebAssembly или в чистом расте?
          0
          На клиенте
            +2
            $ du -h target/wasm32-unknown-unknown/release/todomvc.wasm
            408K target/wasm32-unknown-unknown/release/todomvc.wasm

            --release и после wasm-gc
              0

              Если речь про todomvc, то вот:


            0
            Я бы сказал верный вопрос:
            С чистым WebAssembly или с emscripten

            Сам пытаюсь ответить на этот вопрос)

            TodoMVC Vue.js занимает порядка 100kB
            image

            TodoMVC Yew занимает в dev версии 13Mb, в release версии 1,1Mb
            image

            Собрать TodoMVC с флагами
            `--target=wasm32-unknown-unknown`
            и
            `--target=wasm32-unknown-emscripten`

            я не смог.

            У кого получится — поделитесь рецептом.
              +3
              >в release версии 1,1Mb
              понятно, следующий
                +3
                $ rustup target add --toolchain nightly wasm32-unknown-unknown
                $ cargo +nightly --target=wasm32-unknown-unknown
                  0
                  Спасибо Antti
                  Смог cобрать TodoMVC с флагом `+nightly --target=wasm32-unknown-unknown`
                  395Kb

                  image
                    +3

                    Чтобы ещё "зашакалить" вес результирующего WASM бинарника, используют/-вали wasm-gc, wasm-snip, wasm-opt из binaryen. Детальнее есть в этой статье.
                    Общее желание и тенденция к уменьшению WASM-бинарников наблюдается.


                    К тому же, WASM by design парсится прямо во время скачивания, соответственно у него нет фазы парсинга и компиляции после загрузки, как у JS.

                –6
                Если честно чувствуется усталость от ежедневного появления новых фреймворков.
                Посмотрим на сколько хватит энтузиазма у разработчика.

                  +9
                  А какие ещё есть wasm-фреймворки на расте?
                    0
                    Вообще есть, но не для веба.
                  +1
                  Вы пишете: отладка WebAssembly — это сложный вопрос…

                  Как все таки выглядит процесс разработки целиком? Можно ли ошибки находить и исправлять прямо в браузере ( как при разработке на JS ). Есть ли плагины типа FireBug что ли для того чтобы видеть что там происходит в программе? Как увидеть значения переменных?

                  Кроме браузера — эту программу можно отладить как то еще? В дебагере каком то запустить?
                    0
                    Как все таки выглядит процесс разработки целиком?

                    Если скомпилировалось — значит всё работает и багов нет. Если баг есть — то он в бизнес-логике, и найти его можно просто медитацией над соответствующим кодов.

                    Работая в студии со удобными средствами отладки я раньше и не думал, что такое возможно. Поработав с солидити полгодика, где нет никакой IDE и дебаггера (кроме неработающего remix), просто от безысходности начал ловить баги, просто просматривая исходный код. И то солидити, где у меня куча багов была связанна с отсутствием ошибок при доступе по неинициализированному значению, опечатки в переменных циклов потому что нет нормальных итераторов, и прочих, а то раст…

                    С хорошим типизированным языком можно жить без отладчика, особенно если нет никаких FFI в натив.

                    Кроме браузера — эту программу можно отладить как то еще? В дебагере каком то запустить?

                    Можно дебажить с полноценным таргетом, там дебаггер будет, но браузерное окружение будет эмулироваться, и если баг сильно специфичный для браузера то так его не поймать. Но, как сказано выше, скорее всего этого не произойдет. Компилируемые языки потому и имеют такие «противные» компиляторы, что builds == runs реальная цель, которую они таким образом достигают.
                    +1
                    Все поглядываю на Yew. Честно говоря, пока что использовать «чистый» wasm гораздо удобнее. К сожалению, либо я не внимательно читаю, либо в статье этого нет, в чем приимущество перед «чистым» wasm?
                    Очень хотелось бы какой-либо пошаговый how-to с этим фреймворком. Прям шаг за шагом. Я понимаю, что есть примеры в репе на гитхабе, если несколько статьей около Yew.
                    Но нет никаких блогов/постов о том как шаг-за-шагом создать что-либо более-менее сложнее hello world с использованием сего фреймворка (мне, например, очень интересно, как работать с событийной моделью).
                    Если кто знает такие, буду признателен, если поделитесь линком.
                      +1
                      Если браузер старый, без поддержки WebAssembly, то потребуется emscripten. Это, грубо говоря, эмулятор WebAssembly для браузера.

                      <зануда> Emscripten — это не эмулятор WASM, это LLVM-бекенд для генерации Asm.JS/WASM, JS-рантайм для сгенерированного кода и, видимо, ещё пачка всякого разного (вероятно, включающая и интерпретатор). </зануда>

                        0
                        Тоже самое на D github.com/skoppe/d-wasm-todomvc-poc
                        demo skoppe.github.io/d-wasm-todomvc-poc

                        Исходники куда менее вырвиглазные чем на Rust
                          +3
                          Очень субъективно
                          +2

                          Самое узкое место в производительности веб-приложений — это ресурсоемкие вычисления при отрисовке DOM. Насколько я понимаю, WASM вообще никаким боком тут помочь не может. Зачем нужно городить ui-огород на Rust, если взаимодействие все равно просиходит через то же DOM API что и на JS? По моему, это какое-то нецелевое и малоэффективное использование WASM, хотя, конечно, эксперимент очень интересный.

                            +1

                            Изоморфность?

                            0
                            В Elm мы просто создаем новую модель и отображаем ее на экране. Предыдущая версия модели остается неизменяемой.

                            разве она не будет «подчищена» сборщиком мусора после рендеринга?

                            В том же Elm вряд ли существует проблема какого-то конкурентного доступа. Старая модель нужна только для того, чтобы понять, когда производить рендеринг.

                            А как же концепция time travel?

                            Only users with full accounts can post comments. Log in, please.