Sauron is an html web framework for building web-apps. It is heavily inspired by elm.

Overview

Maintenance

sauron

Latest Version Build Status MIT licensed

sauron

Guide

Sauron is an web framework for creating fast and interactive client side web application, as well as server-side rendering for back-end web applications.

Example

use log::trace;
use sauron::html::attributes::attr;
use sauron::html::text;
use sauron::prelude::*;
use sauron::{Cmd, Component, Node, Program};

#[derive(Debug)]
pub enum Msg {
    Click,
}

pub struct App {
    click_count: u32,
}

impl App {
    pub fn new() -> Self {
        App { click_count: 0 }
    }
}

impl Component<Msg> for App {
    fn view(&self) -> Node<Msg> {
        node! {
            <main>
                <h1>"Minimal example"</h1>
                <div class="some-class" id="some-id" {attr("data-id", 1)}>
                    <input class="client"
                            type="button"
                            value="Click me!"
                            key=1
                            on_click={|_| {
                                trace!("Button is clicked");
                                Msg::Click
                            }}
                    />
                    <div>{text(format!("Clicked: {}", self.click_count))}</div>
                    <input type="text" value={self.click_count}/>
                </div>
            </main>
        }
    }

    fn update(&mut self, msg: Msg) -> Cmd<Self, Msg> {
        trace!("App is updating with msg: {:?}", msg);
        match msg {
            Msg::Click => self.click_count += 1,
        }
        Cmd::none()
    }
}

#[wasm_bindgen(start)]
pub fn main() {
    console_log::init_with_level(log::Level::Trace).unwrap();
    console_error_panic_hook::set_once();
    Program::mount_to_body(App::new());
}

index.html

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
    <title>Minimal sauron app</title>
  </head>
  <body>
    <script type=module>
        import init from './pkg/minimal.js';
        init().catch(console.error);
    </script>
  </body>
</html>

In Cargo.toml, specify the crate-type to be cdylib

[package]
name = "minimal"
version = "0.1.0"
edition = "2018"

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


[dependencies]
sauron = "0.34"
console_error_panic_hook = "0.1"
log = "0.4"
console_log = "0.2"

Build using

$> wasm-pack build --target web --release

Look at the examples and the build script for the details.

Demo examples

  • todomvc The todomvc example
  • futuristic-ui - A demo of futuristic-ui showcasing animation, transition and timed Component update.
  • data-viewer - A resizable spreadsheet CSV data viewer
  • svg-clock - A clock drawn using SVG and window tick event.
  • svg-graph - A simple graph using SVG
  • ultron code-editor - A web-base text-editor with syntax highlighting

Converting HTML into Sauron's syntax

html2sauron - A tool to easily convert html into sauron node tree for your views.

Prerequisite:

cargo install wasm-pack
cargo install basic-http-server

Performance:

Sauron is one of the fastest.

Benchmark Benchmark

Run the benchmark yourself:

Benchmark 1 Benchmark 2

Please support this project:

Become a patron

License: MIT

Comments
  • Button input `onclick` not updating as expected in `view`

    Button input `onclick` not updating as expected in `view`

    Disclaimer: I am very new to Rust, so it is quite likely that the behaviour that I'm describing is totally expected and I'm just getting stumped by my lack of clear understanding of the language.

    I'm seeing unexpected behaviour in how a button input onclick handler functions. The closure is supposed to change during each rerender (i.e. view invocation), based on application state. However, the observed behaviour seems to indicate that the onclick handler that is first set on the input is always used. This is despite the onclick being update multiple times in view. In the same update, the input value is also updated, and this is correctly reflected.

    I made a small app, based off of the minimal Sauron example, which illustrates this: https://github.com/gesterhuizen/sauron-onclick

    The README from that project is duplicated below:

    Steps to reproduce

    1. Clone this repo: https://github.com/gesterhuizen/sauron-onclick
    2. Build it:
    . ./bootstrap.sh
    make build server
    
    1. Open the app in the browser: http://localhost:4001/
    2. Click the button twice.

    Expected

    1. After two button clicks, the VIEW_COUNT on the button and in the text field should be 3. This is expected because the button value and text field reflects the value that VIEW_COUNT held at the time that the view was rendered.
    2. After two button clicks, the number field should be 3. This is expected because, when the button is clicked, the number field is updated with the value that VIEW_COUNT held at the time that the view was rendered. We assign a new onclick closure each time the view is rendered (https://github.com/gesterhuizen/sauron-onclick/blob/master/src/lib.rs#L40):
        fn view(&self) -> Node<Msg> {
            VIEW_COUNT.fetch_add(1, Ordering::SeqCst);
            let vc = VIEW_COUNT.load(Ordering::SeqCst);
    
    ...
                        [input(
                            [
                                r#type("button"),
                                value(format!("VIEW_COUNT: {}", vc)),
                                onclick(move |_| {
                                    sauron::log(format!("Button is clicked (VIEW_COUNT = {})", vc));
                                    Msg::Click(vc)
                                }),
                            ],
                            [],
                        )],
    

    Actual

    1. Expected: After two button clicks, VIEW_COUNT on the button and in the text field is 3 (as expected).
    2. Unexpected: After two button clicks, the number field displays 1 (and stays in this state, no matter how many times the button is clicked). This is unexpected. It seems like first onclick handler that was set (i.e. when VIEW_COUNT held the value 1) is used even after multiple view rerenders.
    wontfix 
    opened by gesterhuizen 9
  • WIP: introduce a node! procedural macro to do html quasi quoting

    WIP: introduce a node! procedural macro to do html quasi quoting

    Hey,

    So this is a project I've been considering doing for a while in genco. But it's not really suitable as a general purpose way to generate HTML. I came across sauron and decided to instead try and incorporate it here.

    This experimental (!) PR adds support for a node! macro to build nodes through html-like quasi quoting, like this:

    impl Model {
        fn view_input(&self) -> Node<Msg> {
            node! {
                <input
                    class="new-todo"
                    id="new-todo"
                    placeholder="What needs to be done?"
                    value={self.value.to_string()}
                    on_input={|v: InputEvent| Msg::Update(v.value.to_string())}
                    on_keypress={|event: KeyboardEvent| {
                        if event.key() == "Enter" {
                            Msg::Add
                        } else {
                            Msg::Nope
                        }
                    }} />
            }
        }
    }
    

    I'm opening this PR to gauge if there's any interest in adding this to the project, or whether I should release it as an external crate. I intend to fix some missing things and add more documentation to the macro. I've also ported the TodoMVC application in case you want to take it for a spin.

    Literal Content

    Since spans aren't stable, interior text content need to be presented as text literals in order to preserve whitespace.

    Like this:

    <h1>"This is a title"</h1>
    

    Alternatively you simply use the text function as before. But a literal could potentially be optimized if we add support for &'static str to Node. This could mean a nice performance boon for certain applications since static strings do not need to be allocated.

    If we ever get stable spans, a similar form of whitespace detection that I've implemented in genco could be used here as well to preserve whitespace and users could simply write:

    <h1>This is a title</h1>
    

    As long as it doesn't contain illegal rust syntax.

    Loops

    I've added somewhat esoteric support for loops, where each value in the block is added as a child (making this sort of a limited templating). I do something similar in genco, and I personally find it nicer than producing a Vec<Node> manually.

    <ul class="todo-list">
        {for (i, e) in self.entries.iter().filter(|e| self.filter.fit(e)).enumerate() {
            view_entry(i, e)
        }}
    </ul>
    

    If you find this too odd, this can be removed.

    TODO

    • [x] Write more documentation and examples.
      • [x] Child interpolation.
      • [x] Child loops.
      • [x] Attribute interpolation.
    • [x] Add support for value-less attributes (like <button disabled>).
    • [ ] Consider adding a custom conversion trait (example name: AddToNode) which would allow for more custom conversion, like Option<T> where T: AddToNode. Something similar exists in genco.
    opened by udoprog 7
  • nodes inserted at position 0 have broken events

    nodes inserted at position 0 have broken events

    the new closures created at view() don't get passed to the corresponding elements instead, every new node acts like the original first node, or panic on keyed nodes

    i made an example code for this problem, also a video preview to illustrate it better

    use {
        sauron::{
            html::text,
            prelude::*,
            Cmd, Application, Node, Program,
        },
    };
    
    struct Container {
        nodes: Vec<u32>,
        last: String
    }
    enum Msg {
        InsertNode,
        AddNode,
        ClickNode(u32)
    }
    
    impl Application<Msg> for Container {
        fn view(&self) -> Node<Msg> {
            let buttons = self.nodes.iter()
                .map(|&x|button([on_click(move |_|Msg::ClickNode(x))],[text(x)])).collect::<Vec<_>>();
            div([],[
                text(&self.last),
                button([on_click(|_|Msg::InsertNode)],[text("add item (broken)")]),
                button([on_click(|_|Msg::AddNode)],[text("add item (working)")]),
                div([id("buttons")],buttons)
            ])
        }
        fn update(&mut self, msg: Msg) -> Cmd<Self, Msg> {
            match msg {
                Msg::InsertNode => self.nodes.insert(0,self.nodes.len() as u32),
                Msg::AddNode => self.nodes.push(self.nodes.len() as u32),
                Msg::ClickNode(pos) => self.last = pos.to_string()
            }
            Cmd::none()
        }
    }
    
    #[wasm_bindgen(start)]
    pub fn main() {
        Program::mount_to_body(
            Container{
                nodes: vec![], 
                last: String::default()
            }
        );
    }
    

    video preview only tested this for position 0 so im not sure about the rest

    opened by vwpix 6
  • Start to fix the build

    Start to fix the build

    Hi there, I was curious about Sauron and started to try to run the examples. I realized then that the compilation is broken in several places. This PR starts to fix some of it (working around the failing warnings). I didn't finish because there were changes to Http::fetch_with_text_response_decoder which I don't understand (and also it was getting to my bedtime). Would be interested in working with someone on fixing these.

    opened by philip-peterson 4
  • input disabled attribute had different behavior that I was expecting in node macro

    input disabled attribute had different behavior that I was expecting in node macro

    I was playing around with some of the examples and was trying to use the macro opposed to the core library functions.

    When attempting to update the buttons in the fetch-data example I noticed that the disabled attribute was not working as I expected.

    <input 
      class="prev_page" 
      type="button" 
      disabled={self.page <= 1}
      value="<< Prev Page"
        on_click=|_| {
        trace!("button is clicked");
        Msg::PrevPage
      }
    />
    

    After expanding and digging into the code I found that we are just passing the attribute and value directly though. Since the HTML behavior is only check if the attribute is present this makes sense.

    It would be nice to see the macro have the same behavior as disabled() from the core library.

    Created pull request #43

    opened by deathbreakfast 3
  • node!(<h1>) syntax does not work on released version 0.32.4">

    node!(

    "example"

    ) syntax does not work on released version 0.32.4

    Compiling the minimal macro syntax example fails if Cargo.toml has sauron = "0.32.4", but succeeds when using the relative path (sauron = { path = "../../"}) or the tagged version directly from Git (sauron = { git = "https://github.com/ivanceras/sauron", tag = "0.32.4" }).

    Build error:

    node! {
        <main>
            <h1>"Minimal example"</h1>
            <div class="some-class" id="some-id" {attr("data-id", 1)}>
    
        </main>
    }
    ^ expected struct `sauron::Text`, found struct `std::string::String`
    

    I narrowed this down to the string literal in the h1 tag: node!(<h1>"example"</h1>). Using the full node!(<h1>{text("example")}</h1>) works with no problem.

    I haven't been able to find a root cause, but I think it has to do with the latest sauron-node-macro version (0.32.0) being released before the fixes in e27c30bc2296a4c139adcb11bdd8a88f61b33f8f. If this is true then releasing a new version with bumped versions should resolve the problem.

    bug 
    opened by sesh22 3
  • Examples don't rub in Safari because wasm_bindgen is undefined

    Examples don't rub in Safari because wasm_bindgen is undefined

    Running one of the examples in Safari leads to an immediate ReferenceError: Can't find variable: wasm_bindgen in the console. If you then immediately type wasm_bindgen into the console REPL, it's defined. You can then copy and paste the loading code wasm_bindgen('pkg/futuristic_ui_bg.wasm').catch(console.error); and the app runs perfectly.

    My guess is that Safari is async loading the first script (which defines wasm_bindgen) and running the second script (which calls it) before the first one is parsed.

    The solution may be to do a dynamic import(...).then(...) chain.

    bug 
    opened by gbj 3
  • Closures attached to similar nodes misbehave

    Closures attached to similar nodes misbehave

    Related to #3, for performance reasons sauron will not recreate a node when it determines via diffing that it can update it instead. In particular it cannot detect whether two closures are equal or not for obvious reasons. However, this leads to strange behavior where event handlers end up on the wrong nodes since the existing nodes were reused instead of being recreated. For an example see https://github.com/cryslith/sauron-reorder. (Use the browser console to see which messages are delivered.)

    One way to handle this could be to use a special attribute like the suggested data-disambiguate to allow specifying to the node diff algorithm that certain nodes should be recreated when data changes. That is, if data-disambiguate differs between the old version and the new version of a node, then the node must be recreated rather than reused.

    opened by cryslith 2
  • How does sauron compare to seed?

    How does sauron compare to seed?

    Hey there, nice job with the framework!

    Currently I am learning Rust by doing a small API for my own hobby project. Once finished I was planning to try to write some frontend with Rust as well. I do have some prior experience with Elm and React stacks and writing production apps with both. So using similar architecture but in Rust feels natural.

    While looking around I've discovered yew and seed, and was thinking to use seed for the job. However now I found out your framework and would love to know more about it. How would you compare it to seed personally?

    opened by gyzerok 2
  • svg tags not showing when using node! macro in the client

    svg tags not showing when using node! macro in the client

    Svg elements is not showing when used in browser. This would be rendered correctly when used server-side.

      <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <pattern id="Pattern" x="0" y="0" width=".25" height=".25">
            <rect x="0" y="0" width="50" height="50" fill="skyblue"/>
          </pattern>
        </defs>
    
        <rect fill="url(#Pattern)" stroke="black" width="200" height="200"/>
      </svg>
    
    
    bug 
    opened by ivanceras 2
  • Benchmarks are misleading and need to be updated.

    Benchmarks are misleading and need to be updated.

    I'm sure that Sauron is fast, but I think the benchmarks are highly misleading. For example, the Vue version (0.10) used in "benchmark 2" is from 2014. I think it's very important to not misrepresent other frameworks if performance is one of the main selling points of Sauron.

    opened by awulkan 2
  • Adding items to a list causes unexpected duplication, and more panics

    Adding items to a list causes unexpected duplication, and more panics

    The following example adds 4 items, but at the end, we end up with 7 items.

    use sauron::prelude::*;
    use wasm_bindgen::prelude::*;
    
    #[wasm_bindgen(start)]
    pub fn start() {
      console_error_panic_hook::set_once();
    
      let p = Program::mount_to_body(App::default());
    
      p.dispatch_with_delay(Msg::AddItem, 1000);
      p.dispatch_with_delay(Msg::AddItem, 2000);
      p.dispatch_with_delay(Msg::AddItem, 3000);
      p.dispatch_with_delay(Msg::AddItem, 4000);
    }
    
    #[derive(Default)]
    struct App {
      items: Vec<Node<Msg>>,
    }
    
    impl Application<Msg> for App {
      fn update(&mut self, msg: Msg) -> Cmd<Self, Msg>
      where
        Self: Sized + 'static,
      {
        match msg {
          Msg::AddItem => self
            .items
            .push(node! { <div>{text(self.items.len() + 1)}</div> }),
        }
    
        Cmd::none()
      }
    
      fn view(&self) -> Node<Msg> {
        node! {
          <div>
            {fragment(self.items.iter().cloned().chain([node! {<span />}]))}
          </div>
        }
      }
    
      fn style(&self) -> String {
        Default::default()
      }
    }
    
    enum Msg {
      AddItem,
    }
    

    Now, for the two panics that are different than the ones discussed in #72, we just need to modify the view method to the following:

        node! {
          <div>
            {fragment(self.items.iter().cloned())}
          </div>
        }
    

    In other words, starting from an empty fragment. The panic is:

    panicked at 'internal error: entered unreachable code: Getting here means we didn't find the element of next node that we are supposed to patch, patch_path: TreePath { path: [0] }',
    

    And finally, removing the surrounding <div /> gives us:

        fragment(self.items.iter().cloned())
    

    The above codes results in:

    panicked at 'must replace node: JsValue(TypeError: getObject(...).replaceWith is not a function
    

    I'm going to be diving into the source and trying to find what's going on.

    opened by jquesada2016 0
  • Panicking when using `node! {}` or `fragment([])`

    Panicking when using `node! {}` or `fragment([])`

    Currently, Sauron is panicking quite a bit, especcially when toggling between children which exist, and children which do not.

    Below is a minimal reproducible example.

    use sauron::prelude::*;
    use wasm_bindgen::prelude::*;
    
    #[wasm_bindgen(start)]
    pub fn start() {
      console_error_panic_hook::set_once();
    
      let p = Program::mount_to_body(App::default());
    
      p.dispatch_with_delay(Msg::ToggleShow, 1000);
      p.dispatch_with_delay(Msg::ToggleShow, 3000);
    }
    
    #[derive(Default)]
    struct App {
      show: bool,
    }
    
    impl Application<Msg> for App {
      fn update(&mut self, msg: Msg) -> Cmd<Self, Msg>
      where
        Self: Sized + 'static,
      {
        match msg {
          Msg::ToggleShow => self.show = !self.show,
        }
    
        Cmd::none()
      }
    
      fn view(&self) -> Node<Msg> {
        if self.show {
          node! { <h1>"Now you see me..."</h1> }
        } else {
          node! {}
        }
      }
    
      fn style(&self) -> String {
        Default::default()
      }
    }
    
    enum Msg {
      ToggleShow,
    }
    

    Nodte that the above also panics when substituting node! {} for fragment([]). The panic that is occurring in this case is:

    panicked at 'Node list must have already been unrolled'
    
    opened by jquesada2016 0
  • FYI: js-framework-benchmark

    FYI: js-framework-benchmark

    @ivanceras I thought it would be nice to see how sauron compares to other framworks.

    So I started an benchmark implementation here: https://github.com/krausest/js-framework-benchmark/pull/1064

    Feel free to comment on this PR draft before I ask for a PR :)

    opened by flosse 0
  • windows-tab-rows demo lags

    windows-tab-rows demo lags

    Hi - if I type quickly into a single field in the windows-tab-rows demo then it immediately lags:

    image

    Is this a restriction of the JS->WASM->JS bridge, or is this unexpected?

    Thanks!

    opened by yatesco 1
Releases(0.40.0)
  • 0.40.0(Aug 15, 2021)

    0.40.0

    • Improve sauron-node-macro performance by resolving the values of namespace and self_closing tags at compile time, rather than at runtime.
    • Add plugin capability of sauron-markdown to easily hook user define functions such as code-highlighting.
    • Modify Window::scroll_to_top to return it as wrapped in Cmd to be used after an update call in a Component
    • Add popstate to events module.
    • Make sauron::jss! macro to create the css without the use of indents and new lines by default.
      • This makes it easier to setup test as we don't have to deal with whitespace anymore.
      • Added sauron::jss_pretty! variant to use nice indents and space on the generated css.
    • breaking Improve the ergonomic to Http api. It is now easier to receive and deserialize text response.
    • Add a code fence processor plugin for sauron-markdown. Developers can hook code to create a custom element out of code blocks in markdown parser.
    • Rename Program::new_replace_mount to Program::replace_mount.
      • Rename Program::new_append_to_mount to Program::append_to_mount.
      • Program is not optional anymore when passed to functions in modules such as apply_patches, dom_updater and created_node
    • Added safe_html to Text node, this indicated whether to render as text node or as innerHTML of its parent element.
      • ammonia crate is used to sanitize the html text.
    • breaking Program agument is not optional anymore in module apply_patches, dom_updater and created_node.
    • Improve rustdoc on prominent functions and modules.
    • Add measurements function to Component for letting components know how much time is spent in each of major steps in dispatching and updating the DOM.
      • Add a field log_measurement to Cmd which tells the Program wheter to log and call measurements.
    • Add performance optimization for sauron-parse crate lookup on tag_namespace and self_closing_tags by putting it in a once_cell Lazy HashSet
    • breaking Rename html_element_sc to html_element_self_closing.
    • breaking Remove the use of underscore_ to html/svg tags such as type_,etc and attributes which are also rust identifier to use the raw r#ident.
      • This includes type for async.
    Source code(tar.gz)
    Source code(zip)
  • 0.7.1(Jun 7, 2019)

    • Added initial implementation for markdown handling
    • Added history function get history object events now prevents defaults and stop propagation
    Source code(tar.gz)
    Source code(zip)
  • 0.7.0(May 20, 2019)

    • Added an initial implementation for Http for fetching data which returns a Cmd
    • Added Examples usage of Http fetch
    • Added Browser for listening to browser resize event which returns a Cmd
    • Added Cmd module for abstracting calls such as Http requests
    • Added an optional init function in Component which allows apps execute Cmd Task such as fetching data at the start of the app
    • Change the update method in Component to return Cmd<Self,Msg> in update method
    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Apr 28, 2019)

    0.6.0

    • Refactor sauron_vdom::Event to cater general usecase for mouse, keyboard and input event
    • Events such as onclick, onkeypress, and oninput are now supplied with: MouseEvent, KeyEvent, and InputEvent accordingly, therefore no additional matching/unwrapping code is neccessary on the users code. Before:
         onclick(|event: Event| {
              if let Event::MouseEvent(mouse) = event{
                  sauron::log!("clicked at ({},{})", mouse.x(), mouse.y())
              }else{
                  panic!("This should not happen")
              }
         })
      

      Now:

          onclick(|mouse: MouseEvent| {
              sauron::log!("clicked at ({},{})", mouse.x(), mouse.y())
          })
      
    • Move to svg_extra the following tags and attributes: style, width, height, id, font_size, font_family, since these conflicts with the commonly used tags and attributes in html. Attributes that are defined in html attributes could also be used in svg attributes. What's not possible is using tags declared in html module in svg elements, since svg elements needs to be created with svg namespace in the DOM.

    0.5.0

    • Use &'static str type for Node's attribute name, event name and namespace.
    • Add helper function styles which allows users to write style properties easily.
    • Add helper function styles_flag which allows users to write even more granular style properties.
    • Elements attributes are now appended to the existing attributes ones, this is needed when there is multiple calls assigning on the same attributes on the same element
    • Put back Callback<Event,MSG> as the value of node.events.
    • Add map functionality which lets user embed subcomponents view into the parent component by mapping the callbacks with a wrapped MSG variant from the parent.

    0.4.0

    • Added the complete list of svg/html attributes.
    • Separate the uncommon html tags into html_extract module. These includes style, which conflicts with the commonly used style attributes.
    • Separate the uncommon attributes such as span, label which conflicts with the commonly used span and label html tags.
    • Use snake_case for non-ident tags and attributes.
    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Apr 28, 2019)

    0.5.0

    • Use &'static str type for Node's attribute name, event name and namespace.
    • Add helper function styles which allows users to write style properties easily.
    • Add helper function styles_flag which allows users to write even more granular style properties.
    • Elements attributes are now appended to the existing attributes ones, this is needed when there is multiple calls assigning on the same attributes on the same element
    • Put back Callback<Event,MSG> as the value of node.events.
    • Add map functionality which lets user embed subcomponents view into the parent component by mapping the callbacks with a wrapped MSG variant from the parent.

    0.4.0

    • Added the complete list of svg/html attributes.
    • Separate the uncommon html tags into html_extract module. These includes style, which conflicts with the commonly used style attributes.
    • Separate the uncommon attributes such as span, label which conflicts with the commonly used span and label html tags.
    • Use snake_case for non-ident tags and attributes.
    Source code(tar.gz)
    Source code(zip)
Owner
Jovansonlee Cesar
I'm for hire. If your company uses rust and interested in one of my projects, please recommend me.
Jovansonlee Cesar
An async no_std HTTP server suitable for bare-metal environments, heavily inspired by axum

picoserve An async no_std HTTP server suitable for bare-metal environments, heavily inspired by axum. It was designed with embassy on the Raspberry Pi

Samuel Hicks 81 Oct 7, 2023
The simplest build-time framework for writing web apps with html templates and typescript

Encoped A build-time fast af tool to write static apps with html and TypeScript Features Template-based ESLint, Prettier and Rollup integration No ext

null 1 Dec 11, 2021
Rust / Wasm framework for building client web apps

Yew Rust / Wasm client web app framework Documentation (stable) | Documentation (latest) | Examples | Changelog | Roadmap | 简体中文文档 | 繁體中文文檔 | ドキュメント A

Yew Stack 25.8k Jan 2, 2023
Silkenweb - A library for writing reactive single page web apps

Silkenweb A library for building reactive single page web apps. Features Fine grained reactivity using signals to minimize DOM API calls No VDOM. Call

null 85 Dec 26, 2022
A Rust library to extract useful data from HTML documents, suitable for web scraping.

select.rs A library to extract useful data from HTML documents, suitable for web scraping. NOTE: The following example only works in the upcoming rele

Utkarsh Kukreti 829 Dec 28, 2022
Thalo is an event-sourcing framework for building large scale systems

Thalo Event sourcing framework for building microservices. Overview Thalo is an event-sourcing framework for building large scale systems based on the

null 548 Jan 3, 2023
A (flash) message framework for actix-web. A port to Rust of Django's message framework.

actix-web-flash-messages Flash messages for actix-web Web applications sometimes need to show a one-time notification to the user - e.g. an error mess

Luca Palmieri 31 Dec 29, 2022
🌱🦀🌱 Trillium is a composable toolkit for building web applications with async rust 🌱🦀🌱

?????? Trillium is a composable toolkit for building web applications with async rust ??????

Trillium 243 Jan 2, 2023
Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix 16.2k Jan 2, 2023
A html document syntax and operation library written in Rust, use APIs similar to jQuery.

Visdom A server-side html document syntax and operation library written in Rust, it uses apis similar to jQuery, left off the parts thoes only worked

轩子 80 Dec 21, 2022
Generate html/js/css with rust

Generate html/js/css with rust

null 79 Sep 29, 2022
Scraper - HTML parsing and querying with CSS selectors

scraper HTML parsing and querying with CSS selectors. scraper is on Crates.io and GitHub. Scraper provides an interface to Servo's html5ever and selec

june 1.2k Dec 30, 2022
jq, but for HTML

hq jq, but for HTML. hq reads HTML and converts it into a JSON object based on a series of CSS selectors. The selectors are expressed in a similar way

Tom Forbes 511 Jan 5, 2023
A blazingly fast HTTP client with a magnificent request building syntax, made for humans.

?? glue Make requests, select JSON responses, nest them in other requests: A magnificent syntax for blazingly fast cli HTTP calls, made for humans. Ta

Michele Esposito 4 Dec 7, 2022
Axum + JWT authentication Middleware that allows you to start building your application fast

axum_jwt_ware Integration Guide Simple Axum + JWT authentication middleware with implemented Login and refresh token. Goal I aim to simplify the proce

Eze Sunday 3 Dec 2, 2023
A Rust web framework

cargonauts - a Rust web framework Documentation cargonauts is a Rust web framework intended for building maintainable, well-factored web apps. This pr

null 179 Dec 25, 2022
A rust web framework with safety and speed in mind.

darpi A web api framework with speed and safety in mind. One of the big goals is to catch all errors at compile time, if possible. The framework uses

null 32 Apr 11, 2022
A web framework for Rust.

Rocket Rocket is an async web framework for Rust with a focus on usability, security, extensibility, and speed. #[macro_use] extern crate rocket; #[g

Sergio Benitez 19.4k Jan 4, 2023
A super-easy, composable, web server framework for warp speeds.

warp A super-easy, composable, web server framework for warp speeds. The fundamental building block of warp is the Filter: they can be combined and co

Sean McArthur 7.5k Jan 2, 2023