Giter Site home page Giter Site logo

draco's Introduction

Draco

Draco is a Rust library to build client side web applications with Web Assembly.

Live Examples with Annotated Source | Starter

Note: This is the README for upcoming Draco 0.2. The README for the latest released version is here.

Overview

The "Hello, World!" of Draco (with comments here):

use wasm_bindgen::prelude::*;

struct HelloWorld;

impl draco::Application for HelloWorld {
    type Message = ();

    fn view(&self) -> draco::VNode<Self::Message> {
        draco::html::h1().with("Hello, world!").into()
    }
}

#[wasm_bindgen(start)]
pub fn start() {
    draco::start(HelloWorld, draco::select("main").expect("<main>").into());
}

Draco is modeled after The Elm Architecture and Redux. A Draco application implements the draco::Application trait, which includes one type and two functions.

pub trait Application {
    type Message;

    fn update(&mut self, message: Self::Message, mailbox: &Mailbox<Self::Message>) {}
    fn view(&self) -> Node<Self::Message>;
}

The view function maps &self to an HTML/SVG Node. The Node can emit Messages on certain events.

The update function takes &mut self, a Message and a draco::Mailbox. This function may update its fields based on the value of the Message. This function may also send more messages to itself or spawn a Future which will send a message when it resolves, through the Mailbox.

Counter

This Counter example (with comments here) demonstrates an application which updates an integer value based on 3 types of messages emitted from the view.

use wasm_bindgen::prelude::*;

#[derive(Default)]
pub struct Counter {
    value: i32,
}

pub enum Message {
    Increment,
    Decrement,
    Reset,
}

impl draco::Application for Counter {
    type Message = Message;

    fn update(&mut self, message: Self::Message, _: &draco::Mailbox<Self::Message>) {
        match message {
            Message::Increment => self.value += 1,
            Message::Decrement => self.value -= 1,
            Message::Reset => self.value = 0,
        }
    }

    fn view(&self) -> draco::VNode<Self::Message> {
        use draco::html as h;
        h::div()
            .with((
                h::button().on("click", |_| Message::Decrement).with("-"),
                " ",
                self.value,
                " ",
                h::button().with("+").on("click", |_| Message::Increment),
                " ",
                h::button().with("Reset").on("click", |_| Message::Reset),
            ))
            .into()
    }
}

#[wasm_bindgen(start)]
pub fn start() {
    draco::start(
        Counter::default(),
        draco::select("main").expect("<main>").into(),
    );
}

draco's People

Contributors

leroycep avatar qthree avatar theduke avatar utkarshkukreti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

draco's Issues

Comparison to Yew wrt updating child state without re-rendering parent's DOM

Am I correct in assuming that draco doesn't have this issue? yewstack/yew#350

IOW, in draco, is it possible to update a child component's state without causing a re-render of the parent's DOM (only causing a re-render of the child whose state actually changed)?

E.g. if my main app element receives ws msgs at 30 fps and each one should be passed down through many layers of components until it modifies some small child's state at the bottom of the component tree, will only that child's DOM be re-rendered, or all intermediate children's DOM, too? (The children in the chain between app->child->...->child->target-child)

(This issue is a huge pain for me with Yew, I'm considering porting my app to draco if it doesn't have this issue.)

Chose a license

That's a very cool project, but it's missing a license. It's usually wise to choose one ๐Ÿ™‚

How to create multiple divs?

All the examples have only one div, and if I have something like this, it doesn't compile:

h::div()
            .push(h::canvas().class("game-canvas"))
            .into()

h::div()
            .push(h::button().push("-").on("click", |_| Message::Decrement))
            .push(self.value)
            .push(h::button().push("+").on("click", |_| Message::Increment))
            .push(h::button().push("Reset").on("click", |_| Message::Reset))
            .into()

fetch

in your git exmaple it appears you can use reqwest. I have issues with using fetch currnetly i would liek to use reqwest as it works when is the release date of version 2 not being pushy just have no clue on how to use github and would liek to try 2.0 to see if this resolves the issue (not used 1.2) another framework?

thanks 1

Destroying an App

Hey, I have the situation that I need to destroy the active app from within update().

As in: clean up everything and remove from the dom.

That does not seem to be possible at the moment.

I guess something like Mailbox::shutdown()

Provide jsx alternative for node construction

I've started to work on a jsx macro for draco.

Thanks to snax this pretty easy to do.

Would you accept a PR that adds a draco_macros proc macro crate with a jsx macro?

I can also publish it as an external crate, but having it official and re-exported (behind a feature flag) would be nicer.

Controlled components not possible

See yewstack/yew#233 (comment) for context.

Essentially, the desired behavior is: if an edit for a field (e.g. an input or text area) is 'rejected' (i.e. not applied to the model), the render should not update. In react this is known as 'controlled components'.

In draco you can test this by applying the patch I've pasted at the bottom and then editing the username input element on the form example. Because the internal state isn't changing, arguably neither should the render. Unfortunately, it does.

React solves this by restoring state after a change event (described on the linked issue). Note that react also provides uncontrolled components where the value field is not set. I think the important thing is that both options are available (somehow).

diff --git a/examples/form.rs b/examples/form.rs
index b70b1d0..bb7c0a7 100644
--- a/examples/form.rs
+++ b/examples/form.rs
@@ -59,7 +59,7 @@ impl draco::App for Form {
                     .attr("id", "username")
                     .attr("name", "username")
                     .attr("value", self.username.clone())
-                    .on_input(Message::UpdateUsername),
+                    /*.on_input(Message::UpdateUsername)*/,
             )
             .push(
                 h::button()

Tests + CI setup

I just noticed draco doesn't have a single test and no CI setup.

I'm willing to help out here but I'm not really familiar with testing WASM projects.

Are there any recommended guidelines for this?

advice

I am thinking of starting with Draco
should i start on 0.2 or the current one its confusing as it says upcoming (with no release date)
i am thinking 0.2 would be a good option would that run on nightly?
sorry if i sound excited i am looking to begin my journey today. But i do not want to go off in the wrong direction.

Implement Router URL parsing API like how `warp` does

The current parsing API is clunky: the parts which don't have a meaningful return value (which return ()) are sent to the map function:

.alt(("posts", query("sort").optional()), |((), sort)| {
    Route::PostIndex { sort }
})

Warp uses some type system magic to flatten the arguments and filter out the ones which return ():

let hi = warp::path("hello")
    .and(warp::path::param())
    .and(warp::header("user-agent"))
    .map(|param: String, agent: String| {
        format!("Hello {}, whose agent is {}", param, agent)
    });

https://docs.rs/warp/0.1.9/warp/index.html

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.